// Psola.cpp: implementation of the CPsola class.
//
//////////////////////////////////////////////////////////////////////////
//			************ PSOLA CLASS *************						//
// This Class contains :												//
//	1. Mathematical functions, such as: Average, Max, Min, Windowing,	//
//	2. Functions support for calculating F0 values						//
//	3. Functions support for concatenating two acoustic Units			//
//	4. Functions support for generating F0 contour						//
//	http://mica.edu.vn:2224/demo/index_2.html																	//
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TDPsola.h"
#include "Psola.h"
#include "MyConstants.h"
#include "WaveFile.h"
#include "Math.h"
#include "TextHandle.h"
#include "TDPsolaDoc.h"
#include "malloc.h"
#include "LXH_Feature_MFCC.h"
#include "LXH_DataIO.h"
#include <stdlib.h> 

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

int		CPsola::m_nErrorCode		= PSL_NOERROR;
WORD	CPsola::m_wVolumeAmp		= 5000;
DWORD	CPsola::m_dwThreshold;
double	CPsola::m_dCoefHeuristic	= 2.5;  //nguong cua ham AMDF
WORD	CPsola::m_wSilenceSize		= 1000;
CMyDatabase CPsola::m_db;
double	CPsola::m_AUTOCORdCoefHeuristic = 0.30;//nguong cua ham tu tuong quan
CString CPsola::m_csError;
int		CPsola::nF0_Begin			= 210;// Bo xung ngay 05 thang 12 nam 2005
float	CPsola::fSpeakingRate		= 1;
int		CPsola::nTypeOfPhrase		= 3;

BOOL	CPsola::BAutoORHand			= TRUE;
BYTE	CPsola::BAutoORHandF0		= 2;
BOOL	CPsola::BSettingInputText	= TRUE;
BYTE	CPsola::bSettingUnitType	= 2;

BOOL	CPsola::B_EnergySmooth		= TRUE;

CString CPsola::CsNameOfWavFile		= "";
CString CPsola::CsNameOfDebugFile	= "";


FRAMEPOSSTRUCT CPsola::FP_OldSyl;

//UNITINFO	CPsola::TempUnit;
/****************************************************************************************/
CPsola::CPsola()
{
}

CPsola::~CPsola()
{

}


/****************************************************************************************/
CString CPsola::GetLastError(int *nErrorCode)
{
	if(nErrorCode) *nErrorCode = m_nErrorCode;
	switch(m_nErrorCode)
	{
		case PSL_ERROR :				return "Error non determinal";
		case PSL_NOTSUPPORTED	:		return "Support only the PCM with 8,16 or 32 bits per sample";
		case PSL_NOTFOUND_F0	:		return "Length of window too short to calculate Fo";
		case PSL_PARAMNOTMATCH	:		return "Contraints between parameters not matched";
		case PSL_NOTENOUGHAFRAME:		return "Signal input not enough a frame";
		case PSL_NULLPOINTER	:		return "Null pointer";
		case PSL_BUFFEROVERFLOW	:		return "Buffer Overflow";
		case PSL_SIGNALTOOSHORT	:		return "Signal is too short";
		case PSL_DB_ERROR		:		return CMyDatabase::GetLastError();
		case PSL_TH_ERROR		:		return CTextHandle::GetLastError();
		case PSL_WF_ERROR		:		return CWaveFile::GetLastError();
		case PSL_PITCHNOTPAIRE	:		return "Pitch not paire : "+m_csError;
		case PSL_PERCENTOVERFLOW:		return "Per cent overflowed";
	}
	return "No Error";
}
/****************************************************************************************/
////////lCount chua so byte cua xau du lieu can chuyen
////////de khong du thua du lieu khi nhap vao so lCount phai chia het cho wBitsPerSample/8
BOOL CPsola::HanningWnd(LPSTR lpSignal, LONG lCount)
{
	if(!lpSignal)
	{
		m_nErrorCode = PSL_NULLPOINTER;
		OutputLastError("Hanning Window error 01!");
		return FALSE;
	}

	if(!lCount)
	{
		m_nErrorCode = PSL_NOERROR;
		return TRUE;
	}

	if(lCount % BYTESPERSAMPLE!=0)
	{
		m_nErrorCode = PSL_PARAMNOTMATCH;
		OutputLastError("Hanning Window error 02!");
		return FALSE;
	}
	
	LONG i;
	LONG lTemp;
	lTemp = lCount/2;
	for(i = 0; i < lCount; i+=2){
		*(short *)(lpSignal + i) = (short)((*(short *)(lpSignal + i)) * (1 + cos(PI*i/lTemp - PI))/2);
	}
	return  TRUE;
}

/****************************************************************************************/
BOOL CPsola::HanningRight(LPSTR lpSignal, DWORD dwMax)
{
	if(!lpSignal)
	{
		m_nErrorCode = PSL_NULLPOINTER;
		OutputLastError("Hanning Window error 03!");
		return FALSE;
	}

	if(!dwMax)
	{
		m_nErrorCode = PSL_NOERROR;
		return TRUE;
	}

	if(dwMax % BYTESPERSAMPLE!=0)
	{
		m_nErrorCode = PSL_PARAMNOTMATCH;
		return NULL;
	}
	
	DWORD i;
	for(i = 0; i < dwMax; i+=2){
		 *(short *)(lpSignal + i) = (short)((*(short *)(lpSignal + i)) * (1 + cos(PI*i/dwMax))/2);// right
		//(short *)(lpSignal + i) = (short)((*(short *)(lpSignal + i)) * (1 + cos(PI*i/dwMax + PI))/2); left
		//(short *)(lpSignal + i) = (short)((*(short *)(lpSignal + i)) * (1 + cos(PI*i/lTemp - PI))/2);
	}
	return  TRUE;
}
/****************************************************************************************/
BOOL CPsola::HanningLeft(LPSTR lpSignal, DWORD dwMax)
{
	if(!lpSignal){
		m_nErrorCode = PSL_NULLPOINTER;
		OutputLastError("Hanning Window error 04!");
		return FALSE;
	}

	if(!dwMax){
		m_nErrorCode = PSL_NOERROR;
		return TRUE;
	}

	if(dwMax % BYTESPERSAMPLE!=0)
	{
		m_nErrorCode = PSL_PARAMNOTMATCH;
		return NULL;
	}
	
	DWORD i;
	for(i = 0; i < dwMax; i+=2){
		*(short *)(lpSignal + i) = (short)((*(short *)(lpSignal + i)) * (1 + cos(PI*i/dwMax + PI))/2);
	}
	return  TRUE;
}
/****************************************************************************************/
LONG CPsola::GetMaxValuePos(LPCTSTR lpSignal, DWORD dwLen, LONG *lMaxValue)
{
	// tra ve vi tri cua gia tri lon nhat; thaodv 180111
	if(!lpSignal){
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}
	if(!dwLen){
		m_nErrorCode = PSL_NOERROR;
		return 0;
	}

	DWORD   i;
	LONG	lValue = 0;
	DWORD	dwMaxPos = 0;
	LONG lTemp;
	
	for(i = 0; i < dwLen; i+=2){
	
		lTemp = (LONG)(*(short *)(lpSignal + i));
		if(lValue < lTemp){
			lValue = lTemp;
			dwMaxPos = i;
		}
	}

	if(lMaxValue) *lMaxValue = (*(short *)(lpSignal + dwMaxPos));
	return dwMaxPos;
	
}

/****************************************************************************************/
LONG CPsola::GetMaxPositiveValuePos(LPCTSTR lpSignal, DWORD dwLen, LONG *lMaxValue)
{
	// tra ve vi tri gia tri duong lon nhat; thaodv 180111
	if(!lpSignal){
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}
	if(!dwLen){
		m_nErrorCode = PSL_NOERROR;
		return 0;
	}

	DWORD   i;
	LONG	lValue = 0;
	DWORD	dwMaxPos = 0;
	LONG lTemp;
	
	for(i = 0; i < dwLen; i+=2){
		lTemp = (LONG)(*(short *)(lpSignal + i));
		if(lTemp <= 0) continue;
		if(lValue < lTemp){
			lValue = lTemp;
			dwMaxPos = i;
		}
	}

	if(lMaxValue) *lMaxValue = lValue;
	return dwMaxPos;
}
/****************************************************************************************/
LONG CPsola::GetMaxNegativeValuePos(LPCTSTR lpSignal, DWORD dwLen, LONG *lMaxValue)
{
	// tra ve vi tri gia tri am lon nhat; thaodv 180111
	if(!lpSignal){
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}
	if(!dwLen){
		m_nErrorCode = PSL_NOERROR;
		return 0;
	}

	DWORD   i;
	LONG	lValue = 0;
	DWORD	dwMaxPos = 0;
	LONG lTemp;
	
	for(i = 0; i < dwLen; i+=2){
		lTemp = (LONG)(*(short *)(lpSignal + i));
		if(lTemp >= 0) continue;
		if(lValue > lTemp){
			lValue = lTemp;
			dwMaxPos = i;
		}
	}

	if(lMaxValue) *lMaxValue = lValue;
	return dwMaxPos;
}
/****************************************************************************************/
int CPsola::GetMinValue(int *nArray, int nCount)
{
	if(!nArray){
		m_nErrorCode = PSL_NULLPOINTER;
		OutputLastError("Get Min Value error 01!");
		return FALSE;
	}
	if(nCount <= 0) return -1;
	int nMin = INT_MAX;
	for (int i = 0; i < nCount;i++)
	{
		if(nMin > nArray[i]) nMin = nArray[i];
	}
	return nMin;
}
/****************************************************************************************/
//Count duoc tinh theo mau
int CPsola::GetMaxValue(int *nArray, int nCount)
{
	if(!nArray){
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}
	ASSERT(nCount > 0);

	int nMax = INT_MIN;
	for (int i = 0; i < nCount;i++)
	{
		if(nMax < nArray[i]) nMax = nArray[i];
	}
	return nMax;
}

/****************************************************************************************/

int CPsola::GetMaxAbsValue(short *nArray,int nCount)
{
	if(!nArray){
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}
	ASSERT(nCount > 0);

	int nMax = 0;
	int nTemp = 0;
	for (int i = 0; i < nCount;i++)
	{
		nTemp = abs(nArray[i]);
		if(nMax < nTemp) nMax = nTemp;
	}
	return nMax;
}



/****************************************************************************************/
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
DWORD CPsola::GetMaxTo(DWORD *lpArray, int nNumber)
{
	DWORD MaxValue = 0;
	DWORD dwTemp;
	for(int i = 1;i<nNumber;i++)
	{	
		dwTemp = lpArray[i] - lpArray[i-1];
		if(MaxValue < dwTemp)
			MaxValue = dwTemp;
	}
	return MaxValue;
}

/****************************************************************************************/
DWORD CPsola::GetAvgTo(DWORD *lpArray, int nNumber)
{
	if(nNumber ==0) return 0;
	if(nNumber ==1) return 0;
	DWORD AvgValue = 0;
	for(int i = 1;i<nNumber;i++)
	{	
		AvgValue += lpArray[i] - lpArray[i-1];
	}
	return AvgValue/(nNumber-1);
}

/****************************************************************************************/
short CPsola::GetAbsAvgValue(short *lpArray, int nNumber)
{
	if(!lpArray) {
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}

	DWORD AvgValue = 0;
	for(int i = 0;i<nNumber;i++)
	{	
		AvgValue += abs(lpArray[i]);
	}
	return (short)(AvgValue/nNumber);
}



/****************************************************************************************/
////////Ham nay tra ve con tro den vi tri cuoi cung cua Frame cuoi cung
////////va tac dong vao mang stFramePos.nPos. va stFramePos.nNumberPos de thiet lap vi tri cac FRAMES
//nNewTo duoc do bang mau
/////////////////////////////////////////////////////////////////////////////////////////
//		Function: SansAccentFromPhone												   //
//		Goal: Calculate position of the elements in a Array of Frames along timeline   //
//			  to control F0 contour from the F0 values and save them into stFramePos   //
//																					   //
//		Input parameters: nNewTo: New F0 value to be synthesized					   //
/////////////////////////////////////////////////////////////////////////////////////////
//thaodv 200111 ?
int CPsola::SansAccentFromPhone( FRAMEPOSSTRUCT &stFramePos, int nNewTo)
{
	ASSERT(stFramePos.nStartPoint % BYTESPERSAMPLE == 0);
	ASSERT(stFramePos.nStartPoint >= 0);
	ASSERT(nNewTo > 0);
	
	if(!stFramePos.nPos) {
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}

	float fNumberPos;
	fNumberPos = float(stFramePos.nSignalLen + stFramePos.nAddition) / (nNewTo * BYTESPERSAMPLE);
	
	int nNumberPos = int(fNumberPos);
	if(fNumberPos > (int(fNumberPos) + 0.5f)) nNumberPos = int(fNumberPos) +1;


	if( nNumberPos > stFramePos.nCount ){
		m_nErrorCode = PSL_BUFFEROVERFLOW;
		return -1;
	}

	stFramePos.nPos[0] = stFramePos.nStartPoint;
	if(nNumberPos == 0)	{ 
		stFramePos.nPos[1] = stFramePos.nStartPoint + nNewTo * BYTESPERSAMPLE;
		///////// Modify 12/05/2006
		stFramePos.nNumberPos = 1;

		return stFramePos.nPos [stFramePos.nNumberPos];

	}

	for(int i = 0; i < nNumberPos; i++)
		stFramePos.nPos[i] = stFramePos.nStartPoint + i * nNewTo * BYTESPERSAMPLE;
	stFramePos.nNumberPos = nNumberPos;
	return  stFramePos.nStartPoint + i * nNewTo * BYTESPERSAMPLE;
}
/****************************************************************************************/
/////////////////////////////////////////////////////////////////////////////////////////
//		Function: AccentGraveFromPhone												   //
//		Goal: Calculate position of the elements in a Array of Frames along timeline   //
//			  to control F0 contour from the given F0 values and save them into		   //
//			  stFramePos 															   //
//		Input parameters: nStartT0/nFinalT0: Initial/Final F0 value of the frame Array //
/////////////////////////////////////////////////////////////////////////////////////////
//thaodv 200111 ?
int CPsola::AccentGraveFromPhone( FRAMEPOSSTRUCT &stFramePos, int nStartTo, int nFinalTo)
{
	ASSERT(stFramePos.nStartPoint % BYTESPERSAMPLE == 0);
	ASSERT(stFramePos.nStartPoint >= 0);
	ASSERT((nStartTo > 0)&&(nFinalTo>0));
	ASSERT(nStartTo <= nFinalTo);
	if(nStartTo == nFinalTo) return SansAccentFromPhone(stFramePos,nStartTo);
	if(!stFramePos.nPos) {
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}

	
	if( (stFramePos.nSignalLen + stFramePos.nAddition) / (nFinalTo * BYTESPERSAMPLE) > stFramePos.nCount ){
		m_nErrorCode = PSL_BUFFEROVERFLOW;
		return -1;
	}

	stFramePos.nPos[0] = stFramePos.nStartPoint;
	if((stFramePos.nSignalLen+stFramePos.nAddition) / (nFinalTo * BYTESPERSAMPLE) == 0)	{ 
		////////////////////////////////////////////////////
		stFramePos.nPos[0] = stFramePos.nStartPoint;
		stFramePos.nPos[1] = stFramePos.nStartPoint + nFinalTo * BYTESPERSAMPLE;
		///////// Modify 12/05/2006
		
		stFramePos.nNumberPos = 1;

		return stFramePos.nPos [stFramePos.nNumberPos]; // Modify 12/05/2006

	}

	int i = stFramePos.nStartPoint;
	stFramePos.nPos[0] = i;
	int j = 1;
	int nAdditiveBegin = nStartTo * BYTESPERSAMPLE;
	int nAdditive = nAdditiveBegin;

	float nHalfStepTo, fStep;
	int nStep;
	
	nHalfStepTo = float(nFinalTo - nStartTo)*(nFinalTo + nStartTo)/(2*((stFramePos.nSignalLen +stFramePos.nAddition)- (nFinalTo - nStartTo)))* BYTESPERSAMPLE;


	int nNumofStep = (2*stFramePos.nSignalLen - (nFinalTo - nStartTo)*BYTESPERSAMPLE)/ 
					 ((nFinalTo + nStartTo)*BYTESPERSAMPLE);
	
	stFramePos.nNumberPos = 0;

	/*for(j=1; j < nNumofStep; j++)
	{
		i += nAdditive ;
		stFramePos.nPos[j] = i;
		nAdditive = nAdditiveBegin + int(j*nHalfStepTo)*BYTESPERSAMPLE;
		//nAdditive += nStepTo;
		stFramePos.nNumberPos++;
	}*/
	
	while(i + nAdditive < stFramePos.nSignalLen+ stFramePos.nAddition + stFramePos.nStartPoint + nFinalTo*BYTESPERSAMPLE)
	{
		i += nAdditive ;
		stFramePos.nPos[j] = i;
		j++;
		//nAdditive = nAdditiveBegin + int(j*nHalfStepTo)*BYTESPERSAMPLE;
		///////////////////////////////////////////////////////////////////
		// Adding 28/12/2006
		fStep = j*nHalfStepTo;
		if(fStep > (int(fStep) + 0.5f)) nStep = int(fStep) +1;
		else nStep = int(fStep);
		nAdditive = nAdditiveBegin + nStep*BYTESPERSAMPLE;
		///////////////////////////////////////////////////////////////////
		//nAdditive += nStepTo;
		stFramePos.nNumberPos++;
	}
	
	/*
	//int nStepTo = stFramePos.nSignalLen  / (nFinalTo - nStartTo + 2 );
	int nStepTo = stFramePos.nSignalLen  / (nFinalTo - nStartTo);
	int nOldStep = i / nStepTo;
	stFramePos.nNumberPos = 0;
	while(i + nAdditive < stFramePos.nSignalLen + stFramePos.nStartPoint)
	{
		i += nAdditive ;
		stFramePos.nPos[j] = i;
		j++;
		if(i / nStepTo != nOldStep)
		{
			nAdditive += (i/nStepTo - nOldStep) * BYTESPERSAMPLE;
			nOldStep = i/nStepTo;
		}
		stFramePos.nNumberPos++;
		
	}*/

	stFramePos.nNumberPos--;
	return  stFramePos.nPos [stFramePos.nNumberPos];
}
/****************************************************************************************/
/////////////////////////////////////////////////////////////////////////////////////////
//		Function: AccentAiguFromPhone												   //
//		Goal: Calculate position of the elements in a Array of Frames along timeline   //
//			  to control F0 contour from the given F0 values and save them into		   //
//			  stFramePos 															   //
//		Input parameters: nStartT0/nFinalT0: Initial/Final F0 value of the frame Array //
/////////////////////////////////////////////////////////////////////////////////////////
int CPsola::AccentAiguFromPhone(   FRAMEPOSSTRUCT &stFramePos, int nStartTo, int nFinalTo)
{
	ASSERT(stFramePos.nStartPoint % BYTESPERSAMPLE == 0);
	ASSERT(stFramePos.nStartPoint >= 0);
	ASSERT((nStartTo > 0)&&(nFinalTo>0));
	ASSERT(nStartTo >= nFinalTo);
	if(nStartTo == nFinalTo) return SansAccentFromPhone(stFramePos,nStartTo);
	if(!stFramePos.nPos) {
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}
	
	if( (stFramePos.nSignalLen+stFramePos.nAddition) / (nFinalTo * BYTESPERSAMPLE) > stFramePos.nCount ){
		m_nErrorCode = PSL_BUFFEROVERFLOW;
		return -1;
	}

	stFramePos.nPos[0] = stFramePos.nStartPoint;
	if((stFramePos.nSignalLen + stFramePos.nAddition) / (nStartTo * BYTESPERSAMPLE) == 0)	{ 
		//////////////////////////
		stFramePos.nPos[0] = stFramePos.nStartPoint;
		stFramePos.nPos[1] = stFramePos.nStartPoint + nStartTo * BYTESPERSAMPLE;
		stFramePos.nNumberPos = 1;
		return stFramePos.nPos [stFramePos.nNumberPos]; // Modify 12/05/2006
		
		/*stFramePos.nNumberPos = 1;
		return nFinalTo * BYTESPERSAMPLE;*/
	}

	int i = stFramePos.nStartPoint;
	stFramePos.nPos[0] = i;
	int j = 1;
	
	int nAdditiveBegin = nStartTo * BYTESPERSAMPLE;
	int nAdditive = nAdditiveBegin;

	float nHalfStepTo, fStep;
	int nStep;
	
	nHalfStepTo = float(nStartTo- nFinalTo)*(nFinalTo + nStartTo)/(2*((stFramePos.nSignalLen+stFramePos.nAddition) - (nStartTo - nFinalTo )))* BYTESPERSAMPLE;

	stFramePos.nNumberPos = 0;

	while(i + nAdditive < stFramePos.nSignalLen + stFramePos.nAddition + stFramePos.nStartPoint + nStartTo*BYTESPERSAMPLE)
	{
		i += nAdditive ;
		stFramePos.nPos[j] = i;
		j++;
		stFramePos.nNumberPos++;
		//nAdditive = nAdditiveBegin - int(j*nHalfStepTo)*BYTESPERSAMPLE;
		///////////////////////////////////////////////////////////////////
		// Adding 28/12/2006
		fStep = j*nHalfStepTo;
		if(fStep > (int(fStep) + 0.5f)) nStep = int(fStep) +1;
		else nStep = int(fStep);
		nAdditive = nAdditiveBegin - nStep*BYTESPERSAMPLE;
		///////////////////////////////////////////////////////////////////

		if(nAdditive < 0) break;
	}
	
	stFramePos.nNumberPos --;
	return  stFramePos.nPos [stFramePos.nNumberPos];
}


/****************************************************************************************/
BOOL CPsola::ChangeAmplitude(LPSTR lpSignal,int nLen, double dCoef)
{
	ASSERT(dCoef > 0);
	ASSERT(nLen % BYTESPERSAMPLE == 0);
	if(!lpSignal) {
		m_nErrorCode = PSL_NULLPOINTER;
		return -1;
	}
	double dw_realvalue =0;
	BOOL MaxFlag= FALSE;

	for(int i = 0; i < nLen ; i+= BYTESPERSAMPLE){
		dw_realvalue = (*(short *)(lpSignal + i)) * dCoef;
		if(dw_realvalue >= 32767.0f) 
		{
			dw_realvalue = 32765;
			MaxFlag = TRUE;
		}
		if(dw_realvalue <= -32767.0f) 
		{
			dw_realvalue = -32765;
			MaxFlag = TRUE;
		}
		*(short *)(lpSignal + i) = (short)dw_realvalue;
		//*(short *)(lpSignal + i) = (short)((*(short *)(lpSignal + i)) * dCoef);
	}

	if(MaxFlag) 
		for(int i = 0; i < nLen ; i+= BYTESPERSAMPLE)
		{
			*(short *)(lpSignal + i) = (short)((*(short *)(lpSignal + i)) * 0.8f);
		}
	return TRUE;
}
/****************************************************************************************/

/****************************************************************************************/
BOOL CPsola::DB_Open(LPCTSTR lpszDBFileName)
{
	BOOL res = m_db.Open(lpszDBFileName);
	if(!res) {
		m_nErrorCode = PSL_DB_ERROR;
		OutputLastError("Open database file error 01!");
		return FALSE;
	}
	return TRUE;
}
/****************************************************************************************/
BOOL CPsola::DB_Close()
{
	m_db.Close();
	return TRUE;

}


/****************************************************************************************/


/////////////////////////////////////////////////////////////////////////////////////////
//		Function: TDPR_PlayText														   //
//		Goal: Analizing input text, looking up in the Database of acoustic units and   //
//			  get the best units to concatenate them into syllable. The syllables then //
//			  are concatenated and stored in the wav file.							   //
//		Input parameters: cs: Syllables or phrases to be synthesized					   //
/////////////////////////////////////////////////////////////////////////////////////////
BOOL CPsola::TDPR_PlayText(CString &cs)
{
	printf("o cho nay 2: %s\n",cs);
	//cout << "this is starting point of function CPsola::TDPR_PlayText(CString &cs) at line 678" << endl; // thaodv 230211
	CTextHandle txt;  // tao mot object cua TextHandle Class. thaodv-070111
	if(!txt.ParseText(cs)) { // goi method ParseText() cua TextHandle; thaodv-070111; neu khogn thanh cong thi bao loi
		m_nErrorCode = PSL_TH_ERROR;
		OutputLastError(GetLastError());
		return FALSE;
	}
	APPENDWAVESTRUCT stAppWave;
	
	char chFileName[256];
	
	strcpy(chFileName, LPCSTR(CsNameOfWavFile));

	int nNumberSyl = txt.GetSylCount(); // lay so Syllable yeu cau ket noi;
	SYLLABLESTRUCT psst, prePsst, folPsst; // For context of Syllable
	WORD i = 0;
	BYTE bPosInSyl = 0;
	
	
	/////////////////////////////////////////////////////////////////////////////////
	//	Bo xung ngay 15 thang 03 nam 2005										   //
	//	Noi dung: Phan tich chuoi dau vao dua ra chuoi dau ra gom cac don vi am.   //
	//			  Cac don vi am nay co tong quang duong la ngan nhat			   //
	//			  Cac don vi am se duoc gan va SYLLABLE de qua do tong hop tung    //
	//			  Syllable theo dau vao cho truoc								   //
	/////////////////////////////////////////////////////////////////////////////////

	/////////////////////////////////////////////////////////////////////////////////
	// Block 1:																	   //
	// This block analyzes the input string and based on BestUnitSelection it will //
	// give a serie of acoustic units.The total distance of this serie is minimum. //
	// The obtained acoustic units will be attached into syllables.				   //
	// This Block is only active when User sellect mode Automatic Sellection	   //
	// Information of the Acoustic Unit: Name of Unit							   //
	//									 Position of Unit in the Database		   //
	/////////////////////////////////////////////////////////////////////////////////
	if(BAutoORHand) // 
	{
		int nBeginOfPhrase=0, nEndOfPhrase=0; // Adding 17/05/2006
		m_db.EmptyBestUnitArray();
		while(i<nNumberSyl)
		{
			psst.wFlag = SYL_FIRSTUNIT | SYL_SECONDUNIT | SYL_NUMBERFO | SYL_SYLLABLELEN|SYL_NUMOFUNIT;
			txt.GetSylInfo(i,psst); // Lay thong tin Syllable tai vi tri thu i
			bPosInSyl = 0;

			if((strlen(psst.cFirstAUnit)==1)&&(psst.cFirstAUnit[0] == '_'))
			{
				if(i!=0) FP_OldSyl.nSignalLen = 0;
				////////////////////////////////////////////////
				// Adding 17/05/2006
				// 
				////////////////////////////////////////////////
				if(psst.nSyllableLen>=7000)
				{
					nEndOfPhrase = i;
					
					if(nBeginOfPhrase < nEndOfPhrase) m_db.ListSelUnit(); // Take candidate acoustic units in the data base
				
					int nCounter = 0;
					int nSylNum = nBeginOfPhrase;
					while(nSylNum < nEndOfPhrase)
					{
						psst.wFlag = SYL_FIRSTUNIT | SYL_SECONDUNIT | SYL_NUMBERFO | SYL_SYLLABLELEN|SYL_NUMOFUNIT;
						txt.GetSylInfo(nSylNum,psst); // Lay thong tin Syllable tai vi tri thu i

						if((strlen(psst.cFirstAUnit)==1)&&(psst.cFirstAUnit[0] == '_'))
						{
							nSylNum++;
							continue;
						}

						for(int UnitNo=0; UnitNo < psst.nAUnit; UnitNo++)
						{
							psst.bUnitIndex[UnitNo] = m_db.GetPosBestUnit(nCounter);
							nCounter++;
						}
						txt.UpdateSylInfo(nSylNum,psst);
						nSylNum++;
					}
					nBeginOfPhrase = nEndOfPhrase +1;
					m_db.EmptyBestUnitArray();
				}

				// end of adding 17/05/2006

				i++;
				continue;
			}
			//////////////////////////////////////////
			psst.nTon = 0;

			if(psst.nNumberFo >0)
			{
				psst.nFo = new int [psst.nNumberFo + 1];
				psst.wFlag =  SYL_FOARRAY|SYL_ENERGY|SYL_TON;// them SYL_TON 31/08/2005
				txt.GetSylInfo(i,psst);
			}
			else 
			{
				if(psst.nSyllableLen>0) psst.nTon =1;
				psst.nFo = new int [2];
				psst.nNumberFo = 0;
			}
			/////////////////////////////////////////////////////////////////////
		//	Require a function to analyse the context of the synthethic acoustic Unit
		//	Get the context of Unit
			if(i>0) 
			{
				prePsst.wFlag = SYL_FIRSTUNIT | SYL_SECONDUNIT | SYL_NUMBERFO | SYL_NUMOFUNIT | SYL_SYLLABLELEN;
				txt.GetSylInfo(i-1,prePsst); // Lay thong tin Syllable tai vi tri thu i
				if((strlen(prePsst.cFirstAUnit)==1)&&(prePsst.cFirstAUnit[0] == '_'))
				{
					memcpy(prePsst.cFirstAUnit, "SIL",3);
					prePsst.cFirstAUnit[3] = '\0';
					prePsst.nAUnit = 1;
					prePsst.nTon = 0;
				}
				if(prePsst.nNumberFo >0)
				{
					prePsst.nFo = new int [prePsst.nNumberFo + 1];
					prePsst.wFlag =  SYL_FOARRAY | SYL_ENERGY | SYL_TON;
					txt.GetSylInfo(i-1,prePsst);
				}
				else 
				{
					if(prePsst.nSyllableLen>0) prePsst.nTon = 1;
					prePsst.nFo = new int [2];
					prePsst.nNumberFo = 0;
				}
			}
			if(i<nNumberSyl-1) 
			{
				folPsst.wFlag = SYL_FIRSTUNIT | SYL_SECONDUNIT | SYL_NUMBERFO |SYL_NUMOFUNIT;
				txt.GetSylInfo(i+1,folPsst);
				if((strlen(folPsst.cFirstAUnit)==1)&&(folPsst.cFirstAUnit[0] == '_'))
				{
					memcpy(folPsst.cFirstAUnit, "SIL",3);
					folPsst.cFirstAUnit[3] = '\0';
					folPsst.nAUnit = 1;
					folPsst.nTon = 0;
				}
				if(folPsst.nNumberFo >0)
				{
					folPsst.nFo = new int [folPsst.nNumberFo + 1];
					folPsst.wFlag =  SYL_FOARRAY|SYL_ENERGY|SYL_TON;//
					txt.GetSylInfo(i+1,folPsst);
				}
				else 
				{
					if(folPsst.nSyllableLen>0) folPsst.nTon =1;
					folPsst.nFo = new int [2];
					folPsst.nNumberFo = 0;
				}
			}
		//	}
			bPosInSyl ++;
			/////////////////////////////////////////////////////////////////////////////////
			UNITINFO stUnitInfo; 
			sprintf(stUnitInfo.cUnitName,"%s",psst.cFirstAUnit); // Copy ten cua AUnit dau vao stUnitInfo
			cout<<"line 838: Psola: "<<stUnitInfo.cUnitName<<endl;
			
			if(i==0)
				m_db.GetUnitContext(psst,prePsst,folPsst, stUnitInfo,1,bPosInSyl);
			else
				m_db.GetUnitContext(psst,prePsst,folPsst, stUnitInfo,4,bPosInSyl);
					
			if(!m_db.BestUnitSelection(stUnitInfo))
			{
				m_nErrorCode = PSL_DB_ERROR;

				OutputLastError(GetLastError());
				txt.RemoveAt(i);
				nNumberSyl--;
				continue;
				//return FALSE;
			}
					
			if(psst.nAUnit >=2)
			{
				// Get context of Unit
				sprintf(stUnitInfo.cUnitName,"%s",psst.cSecondAUnit);
				if(i<nNumberSyl - 1)
				{
					if(psst.nAUnit == 2)
						m_db.GetUnitContext(psst,prePsst,folPsst, stUnitInfo,3,bPosInSyl);
					else
					{
						bPosInSyl =2;
						m_db.GetUnitContext(psst,prePsst,folPsst, stUnitInfo,2,bPosInSyl);
					}
				}
				else
					m_db.GetUnitContext(psst,prePsst,folPsst, stUnitInfo,5,bPosInSyl);
				if(!m_db.BestUnitSelection(stUnitInfo))
				{
					m_nErrorCode = PSL_DB_ERROR;
			
					CString csErrorOut;
					csErrorOut = GetLastError();
					OutputLastError(csErrorOut);
					txt.RemoveAt(i);
					nNumberSyl--;
					continue;
					//return FALSE;
				}
			}
		
			
			i++;
		}

		if((i==nNumberSyl)&&(nBeginOfPhrase < i))
		{
			nEndOfPhrase = i;
			if(nBeginOfPhrase < nEndOfPhrase) m_db.ListSelUnit(); // Take candidate acoustic units in the data base
				
			int nCounter = 0;
			int nSylNum = nBeginOfPhrase;
			while(nSylNum < nEndOfPhrase)
				{
				//	DIPDISINFO BestUnit; 
					psst.wFlag = SYL_FIRSTUNIT | SYL_SECONDUNIT | SYL_NUMBERFO | SYL_SYLLABLELEN|SYL_NUMOFUNIT;
					txt.GetSylInfo(nSylNum,psst); // Lay thong tin Syllable tai vi tri thu i
					if((strlen(psst.cFirstAUnit)==1)&&(psst.cFirstAUnit[0] == '_'))
					{
						nSylNum++;
						continue;
					}
					for(int UnitNo=0; UnitNo < psst.nAUnit; UnitNo++)
					{
						psst.bUnitIndex[UnitNo] = m_db.GetPosBestUnit(nCounter);
						nCounter++;
					}
					txt.UpdateSylInfo(nSylNum,psst);
					nSylNum++;
					}

		}
		

	}
	// Bo xung cac thong tin ve don vi am

	/////////////////////////**** End of Block 1****/////////////////////////////////

	/////////////////////////////////////////////////////////////////////////////////
	//	Ket thuc Bo xung ngay 15 thang 03 nam 2005								   //
	/////////////////////////////////////////////////////////////////////////////////
	
	/////////////////////////////////////////////////////////////////////////////////
	// Block 2:																	   //
	// Syllables are synthesized from the serie of acoustic Unit analyzed above.   //
	// Each syllable can be composed of from 2 to 4 concatenated units. The number //
	// of units depends on synthesized unit type: if Demi-syllable : number = 2	   //
	//											  if Dephone : number = 2-4		   //
	/////////////////////////////////////////////////////////////////////////////////

	i=0;
	while(i<nNumberSyl)
	{
		psst.wFlag = SYL_FIRSTUNIT | SYL_SECONDUNIT | SYL_NUMBERFO | SYL_SYLLABLELEN|SYL_NUMOFUNIT;
		txt.GetSylInfo(i,psst); // Get information of syllable at index i.
		bPosInSyl = 0;

		if((strlen(psst.cFirstAUnit)==1)&&(psst.cFirstAUnit[0] == '_')) // check the input syllable to be a silence signal or not
		{
			if(psst.nSyllableLen <= 0) psst.nSyllableLen = m_wSilenceSize; // Neu la doan 
																// Silence thi copy vao du lieu
			psst.lpNewSyllable = new char [psst.nSyllableLen];
			memset(psst.lpNewSyllable,0,psst.nSyllableLen);
			if(i==0)
			{
				if(!CWaveFile::CreateWaveFile(CsNameOfWavFile,SAMPLERATE,BITSPERSAMPLE,1,psst.nSyllableLen,psst.lpNewSyllable))
				{
					delete[] psst.lpNewSyllable;		
					m_nErrorCode = PSL_WF_ERROR;
					OutputLastError(GetLastError());
					return FALSE;
				}
			}
			else
			{
		 		stAppWave.lpSignal = psst.lpNewSyllable;
				stAppWave.dwLen = psst.nSyllableLen;
				stAppWave.lpszFileName	= chFileName;
				stAppWave.uSampleRate = SAMPLERATE;
				stAppWave.wBitsPerSample = BITSPERSAMPLE;
				stAppWave.wNumberChannels = 1;
				CWaveFile::AppendToWaveFile(stAppWave);
				FP_OldSyl.nSignalLen = 0;
			}
			i++;
			delete[] psst.lpNewSyllable;
			continue;
		}
		//////////////////////////////////////////
		psst.nTon = 0;
		if(psst.nNumberFo >0)
		{
			psst.nFo = new int [psst.nNumberFo + 1];
			psst.wFlag =  SYL_FOARRAY|SYL_ENERGY|SYL_TON;// them SYL_TON 31/08/2005
			txt.GetSylInfo(i,psst);
		}
		else 
		{
			if(psst.nSyllableLen>0) psst.nTon =1;
			psst.nFo = new int [2];
			psst.nNumberFo = 0;
		}

		/////////////////////////////////////////////////////////////////////
		bPosInSyl ++;
		/////////////////////////////////////////////////////////////////////////////////
		UNITINFO stUnitInfo; 
		sprintf(stUnitInfo.cUnitName,"%s",psst.cFirstAUnit); // Copy ten cua AUnit dau vao stUnitInfo

		stUnitInfo.wFlag = DB_DIPNAME | DB_DIPLEN; // Set Flag
		stUnitInfo.bSameUnitIndex = psst.bUnitIndex[0];
				
		if(!m_db.GetAUnitInfo(stUnitInfo)) // Get information of Unit from Database
		{
			m_nErrorCode = PSL_DB_ERROR;
			OutputLastError("Acoustic Unit not found 4!");

			delete[] psst.nFo;
			txt.RemoveAt(i);
			nNumberSyl--;
			continue;
			
			//return FALSE;
		}
	
		DWORD dwOrgSylLen = stUnitInfo.dwDipLen; // Chieu dai cua AUnit thu nhat
		
		//////////////////////////////////////////////////////////////
		//			Bo xung ngay 10/02/2005							//
		//			Noi dung: Sua de co the lam voi phan van		//
		//////////////////////////////////////////////////////////////
		if(psst.nAUnit >=2)
		{
			// Get context of Unit
			sprintf(stUnitInfo.cUnitName,"%s",psst.cSecondAUnit);
			stUnitInfo.wFlag = DB_DIPNAME | DB_DIPLEN;
			stUnitInfo.bSameUnitIndex = psst.bUnitIndex[1];
	
			if(!m_db.GetAUnitInfo(stUnitInfo)) 
			{
				m_nErrorCode = PSL_DB_ERROR;
				OutputLastError(GetLastError());
				return FALSE;
			}
			dwOrgSylLen += stUnitInfo.dwDipLen; // Chieu dai cua 2 AUnit ghep lai
		}
		// Hai cum lenh tren la de lay thong tin ve chieu dai va kiem tra xem AUnit co trong
		// CSDL khong

		///////////////////////////////////////////////////////////////////////////////////////

		if(psst.nSyllableLen < 4000) // The default minimum length = 4000
		{
			psst.nSyllableLen = dwOrgSylLen;
		}

		psst.lpNewSyllable = new char [psst.nSyllableLen]; //Tao mang de tao syllable moi

		////////////////////////////////////////////////////////////////////////////////////////
		// danh cho tao mo phong duong cong F0
		////////////////////////////////////////////////////////////////////////////////////////

		
		FRAMEPOSSTRUCT FP_PreSyllable;
		if(B_EnergySmooth && (i>0)) // For smoothing amplitude of synthesized syllable
		{
			FP_PreSyllable.nNumberPos = FP_OldSyl.nNumberPos;
			FP_PreSyllable.nSignalLen = FP_OldSyl.nSignalLen;
			FP_PreSyllable.nTransPoint= FP_OldSyl.nTransPoint;
			FP_PreSyllable.nPos = new int[FP_PreSyllable.nNumberPos];

			for(int k = 0; k < FP_PreSyllable.nNumberPos; k++)
				FP_PreSyllable.nPos[k] = FP_OldSyl.nPos[k];
			delete[] FP_OldSyl.nPos;
		}		
		
		if(!CPsola::CreateSyllable(psst)) // Create a syllable from its elements (acoustic units) 
		{
			delete[] psst.nFo;
			delete[] psst.lpNewSyllable;
			OutputLastError("Create Syllable does not work well");
			return FALSE;
		}

		if(B_EnergySmooth)
		{
			CString ListOfVowel = "iMue7oEaOZABQIUY";
			if(i<nNumberSyl-1) // Adding 18/05/2006 smoothing the last syllable
			{
				folPsst.wFlag = SYL_FIRSTUNIT | SYL_SECONDUNIT | SYL_NUMBERFO |SYL_NUMOFUNIT;
				txt.GetSylInfo(i+1,folPsst);
				if((strlen(folPsst.cFirstAUnit)==1)&&(folPsst.cFirstAUnit[0] == '_'))
					HanningRight(psst.lpNewSyllable + psst.nSyllableLen*7/16*BYTESPERSAMPLE,psst.nSyllableLen- psst.nSyllableLen*7/16*BYTESPERSAMPLE);
			}
			if(i==(nNumberSyl-1)) // Adding 18/05/2006 smoothing the last syllable
			{
				HanningRight(psst.lpNewSyllable + psst.nSyllableLen*7/16*BYTESPERSAMPLE,psst.nSyllableLen- psst.nSyllableLen*7/16*BYTESPERSAMPLE);
			}
			if((i==0)||(FP_PreSyllable.nSignalLen==0))
			{
				int nVowelPos = ListOfVowel.Find(psst.cFirstAUnit[1],0);
				if(nVowelPos != -1) 
					HanningLeft(psst.lpNewSyllable, psst.nSyllableLen/16*BYTESPERSAMPLE);
				else
					HanningLeft(psst.lpNewSyllable, (int)(FP_OldSyl.nTransPoint/4)*2);
			}
			else
			{
				if(!EnergySmooth(FP_PreSyllable,FP_OldSyl,psst))
				{
					delete[] FP_PreSyllable.nPos;
					delete[] FP_OldSyl.nPos;
					delete[] psst.nFo;
					delete[] psst.lpNewSyllable;
					OutputLastError("Energy Smooth does not work well!");
					return FALSE;
				}
				else
					delete[] FP_PreSyllable.nPos;// added 23/9/2009
			}
			
		}


		if(i==0)
		{
			if(!CWaveFile::CreateWaveFile(CsNameOfWavFile,SAMPLERATE,BITSPERSAMPLE,1,psst.nSyllableLen,psst.lpNewSyllable))
			{
				delete[] psst.nFo;
				delete[] psst.lpNewSyllable;
				m_nErrorCode = PSL_WF_ERROR;
				OutputLastError(GetLastError());
				return FALSE;
			}
		}
		else
		{
			stAppWave.lpSignal = psst.lpNewSyllable;
			stAppWave.dwLen = psst.nSyllableLen;
			stAppWave.lpszFileName	= chFileName;
			
			stAppWave.uSampleRate = SAMPLERATE;
			stAppWave.wBitsPerSample = BITSPERSAMPLE;
			stAppWave.wNumberChannels = 1;
			CWaveFile::AppendToWaveFile(stAppWave);
		}
		delete[] psst.nFo;
		delete[] psst.lpNewSyllable;
		i++;
	}
	// Free memory
	txt.PhoneArray.RemoveAll();	
	txt.InPhoneArray.RemoveAll();
	txt.MiPhoneArray.RemoveAll();
	txt.VoArray.RemoveAll();
	txt.FiPhoneArray.RemoveAll();
	txt.DicSyllableArray.RemoveAll();



	if(i) 
	{
		CWaveFile fWaveFile;
		if(!fWaveFile.Attach(CsNameOfWavFile))
		{
			m_nErrorCode = PSL_WF_ERROR;
			OutputLastError(GetLastError());
			return FALSE;
		}
		DWORD dwSize = fWaveFile.GetDataSize();
		char *lpWave = new char [dwSize];
		if(!fWaveFile.SeparateData(lpWave,NULL,dwSize))
		{
			m_nErrorCode = PSL_WF_ERROR;
			delete[] lpWave;
			OutputLastError(GetLastError());
			return FALSE;
		}

		WAVEFORMATEX m_wvx;
		m_wvx.cbSize = 0;
		m_wvx.nSamplesPerSec = SAMPLERATE;
		m_wvx.nChannels = 1;
		m_wvx.wBitsPerSample = BITSPERSAMPLE;
		m_wvx.nBlockAlign = m_wvx.nChannels * (m_wvx.wBitsPerSample / 8);
		m_wvx.nAvgBytesPerSec = m_wvx.nSamplesPerSec * m_wvx.nBlockAlign; 
		m_wvx.wFormatTag = WAVE_FORMAT_PCM;

		delete[] lpWave;
	}

	return TRUE;
	
}

/****************************************************************************************/
//////////////////////////////////////////////////////////////////////////////////////////////

BOOL CPsola::CreateSyllable(SYLLABLESTRUCT &stSyllable)
{
	//ASSERT((strlen(stSyllable.cFirstDiphone) < 5)&&(strlen(stSyllable.cSecondDiphone) < 5));
	int counter; // bien dem bat ki, bo xung ngay 21/10/2004
	int nNumOfUnitPerSyl;// = 4; // bien nay dung de test so Unit duoc ket noi de tao thanh syllable
						  // lay gia tri tu 1 den 4;
	int UnitType[4]={0,0,0,0};// = {1,2,2,1}; // day la mot mang no se dai dien cho kieu Unit cua cac AUnit,
					 // bien nay duoc dung thu, sau khi hoan thien se duoc thay doi bang 
					 // cach tich hop ngay ben trong Unit
	
	BOOL B_SyllabeType = FALSE; // Bo xung ngay 23 thang 03 nam 2003 de xac nhan kieu tong hop su dung
								// don vi am la Syllable
	///////////////////////////////////////////////////////////////////////////////////////////
	// Bo xung ngay 09 thang 05 nam 2006		//
	// Noi dung: Phan tich text dau vao			//
	// Ten bien : ListOfVowel
	///////////////////////////////////////
	CString ListOfVowel = "iMue7oEaOZABQIUY";


	nNumOfUnitPerSyl = stSyllable.nAUnit;
	
	//////////////////////////////////////////////////////////////////
	//		Bo xung ngay 21/10/2004									//
	//		Noi dung: Ko dong y voi bo xung 16/10 sua bang 1 mang   //
	//				  cho linh dong hon								//
	//////////////////////////////////////////////////////////////////
	UNITINFO Unit[4]; // bo xung ngay 21/10
	
	for (counter = 0; counter < nNumOfUnitPerSyl; counter++)
	{
		Unit[counter].wFlag = DB_DIPNAME | DB_DIPBUFFER | DB_DIPLEN | DB_DIPTRANPOINT | DB_DIPMARKS | DB_DIPNUMBERMARKS;
	}
		
	memcpy(Unit[0].cUnitName,stSyllable.cFirstAUnit,5);
	Unit[0].cUnitName[4] =	'\0';
	Unit[0].bSameUnitIndex = stSyllable.bUnitIndex[0];
	//////////////////////////////////////////////////////////////////
	//		Bo xung ngay 10/02/2005									//
	//		Noi dung: Bo xung dieu kien de co the ap dung cho 1     //
	//				  don vi am										//
	//////////////////////////////////////////////////////////////////
	if (nNumOfUnitPerSyl >= 2)
	{
		memcpy(Unit[1].cUnitName,stSyllable.cSecondAUnit,5);
		Unit[1].cUnitName[4]=	'\0';
		Unit[1].bSameUnitIndex = stSyllable.bUnitIndex[1];
	}
	// chac chan so unit se =2 tro len;

	/**************************************************************************/
	
	for (counter =0; counter < nNumOfUnitPerSyl; counter++)
	{ 
		if(	!m_db.GetAUnitInfo(Unit[counter]))
		{
			//MessageBox(::AfxGetMainWnd()->m_hWnd,CPsola::GetLastError().GetBuffer(0),0,MB_OK | MB_ICONEXCLAMATION);
			m_nErrorCode = PSL_DB_ERROR;
			
			CString csTempOut1;
			csTempOut1 = CPsola::GetLastError();
			OutputLastError(csTempOut1);
			
			return FALSE;
		}
		else
		{
			if(Unit[counter].nNumberPitchMarks == 0)// truong hop Unvoice
				UnitType[counter] = 1;
			else UnitType[counter] = 2;
			
		}
	}
	//////////////////////////////////////////////////////////////////
	//		Bo xung ngay 21/10/2004									//
	//		Noi dung: Bo xung dieu kien de co the ap dung cho 1     //
	//				  don vi am										//
	//////////////////////////////////////////////////////////////////
	if(nNumOfUnitPerSyl ==1)
	{
		if(UnitType[0] == 1)
		{
			m_nErrorCode = PSL_DB_ERROR;
			OutputLastError(GetLastError());
			return FALSE;
		}
		else 
		{
			UNITINFO Silence;
			
			//Silence.wFlag = DB_DIPNAME | DB_DIPBUFFER | DB_DIPLEN | DB_DIPTRANPOINT | DB_DIPMARKS | DB_DIPNUMBERMARKS;
			strcpy(Silence.cUnitName,"SIL");
			Silence.dwDipLen = BYTESPERSAMPLE;
			Silence.nTranPoint = 0;
			Silence.nNumberPitchMarks = 0;
			Silence.lpBuffer = new char [BYTESPERSAMPLE];
			memset(Silence.lpBuffer,0,BYTESPERSAMPLE);
			Silence.lpPitchMarks = new DWORD [1];
			memset(Silence.lpPitchMarks,0,BYTESPERSAMPLE);
			Silence.bTone = 0;
			Silence.bLeftTone = 0;
			Silence.bRightTone = 0;
			Silence.dwHighFEnergy = 0;
			Silence.dwLowFEnergy  =0;
			strcpy(Silence.cLeftUnitName,"SIL");
			strcpy(Silence.cRightUnitName,"SIL");
						
			Unit[1] = Silence;
			B_SyllabeType = TRUE;
			stSyllable.nSyllableLen = stSyllable.nSyllableLen + Unit[1].dwDipLen; // Bo xung 23 thang  03
			delete [] stSyllable.lpNewSyllable;
			stSyllable.lpNewSyllable = new char[stSyllable.nSyllableLen];
			nNumOfUnitPerSyl ++;
		}
	}
	///////////////////////////////////////////////////////////////////
	
	UNITINFO TempDip1, TempDip2;

	// Kiem tra kieu du lieu, neu la HalfSyllable (FALSE) hay la Syllable (TRUE)
	if(B_SyllabeType == FALSE)
	{
		TempDip1 = Unit[0];
		TempDip2 = Unit[1];
	}
	else
	{
		TempDip1 = Unit[1];
		TempDip2 = Unit[0];
	}

	
	/**************************************************************************************/
	////////////////////////////////////////////////////////////////////////////////////////
	//				Sua doi ngay 12 thang 11 nam 2004									  //
	//			Noi dung: sua de co the tong hop duoc ca loai INITIAL and FINAL			  //
	////////////////////////////////////////////////////////////////////////////////////////
	BOOL B_TypeCnFlag = TRUE; // true : Connecting 2 units with modifying the F0 of both
							// False : Connecting Initial and final parts
	if(TempDip1.nNumberPitchMarks == 0) B_TypeCnFlag = FALSE;

	/**************************************************************************************/
	
	char *m_cTemplate;// = new char [stSyllable.nSyllableLen + PSL_SAFEBUFFER * 2];
	PHONESTRUCT stPhone;
	
	int nOldSyllableLen = 0;


	// Bo xung ngay 12 thang 11 nam 2004
	if(B_TypeCnFlag)
	{
		stPhone.lHandlePoint = TempDip1.lpPitchMarks[0]* BYTESPERSAMPLE;	// Version 2.0 ngay 11 thang 09 nam 2005. 
		if(TempDip1.nTranPoint > TempDip1.lpPitchMarks[0])
			stPhone.fTransitionPoint = float(TempDip1.nTranPoint * BYTESPERSAMPLE)/(TempDip1.dwDipLen+TempDip2.dwDipLen);	// Version 2.0 ngay 11 thang 09 nam 2005. 
		else 
			stPhone.fTransitionPoint = 0;
														// Vi stPhone da tro vao m_cTemplate, nen du lieu da duoc nap 
														// vao stPhone.lpBuffer se duoc nap vao m_cTemplate
		////////////////////////////////////////////////
		// Bo xung cho am nang		//
		// ngay 15 thang 09 nam 2005 //
		///////////////////////////////
		
		stPhone.lNewHandleLen = stSyllable.nSyllableLen - TempDip1.lpPitchMarks[0] * 2  
								- (TempDip2.dwDipLen - TempDip2.lpPitchMarks[TempDip2.nNumberPitchMarks-1] * 2);//tai sao phai nhan 2???
								//- (TempDip2.dwDipLen - TempDip2.nTranPoint * 2);//tai sao phai nhan 2???
														// Tra loi: vi ma hoa 2byte =16bit
														// Do dai vung tin hieu moi sau khi hieu chinh
														// tan so tu vung HandleLen

		// Bo xung ngay 23 thang 03 nam 2005
	
		if (stPhone.lNewHandleLen <0)
		{
			stSyllable.nSyllableLen = TempDip1.dwDipLen + TempDip2.dwDipLen;
			stPhone.lNewHandleLen = stSyllable.nSyllableLen - TempDip1.lpPitchMarks[0] * 2  
								- (TempDip2.dwDipLen - TempDip2.lpPitchMarks[TempDip2.nNumberPitchMarks-1] * 2);//Sua ngay 25 thang 09 nam 2007

			
			delete [] stSyllable.lpNewSyllable;
			stSyllable.lpNewSyllable = new char[stSyllable.nSyllableLen];

		}
		//KT bo xung
		///////////////////////////////////////////////
		// Bo xung cho am nang			//
		// ngay 15 thang 09 nam 2005	//
		//////////////////////////////////
		if(stSyllable.nTon == 6)
		{
			nOldSyllableLen		= stSyllable.nSyllableLen;
			stSyllable.nSyllableLen	= stSyllable.nSyllableLen + int(stPhone.lNewHandleLen/4)*BYTESPERSAMPLE;// Adding 1/2 length value of stPhone.lNewHandleLen;
			stPhone.lNewHandleLen	= int(3*stPhone.lNewHandleLen/4)*BYTESPERSAMPLE;
		}
			
	}
	else
	{
		stPhone.lHandlePoint = TempDip1.dwDipLen + TempDip2.lpPitchMarks[0]*  BYTESPERSAMPLE;
		if(TempDip2.nTranPoint > TempDip2.lpPitchMarks[0])
			stPhone.fTransitionPoint = float(TempDip1.dwDipLen + TempDip2.nTranPoint * BYTESPERSAMPLE)
										 /(TempDip1.dwDipLen+TempDip2.dwDipLen);// Version 2.0 ngay 11 thang 09 nam 2005. 
		else
			stPhone.fTransitionPoint = 0;
			
		stPhone.lNewHandleLen = stSyllable.nSyllableLen - TempDip1.dwDipLen - TempDip2.lpPitchMarks[0]*2 - 
								(TempDip2.dwDipLen - TempDip2.lpPitchMarks[TempDip2.nNumberPitchMarks -1] * 2);// Sua ngay 24 thang 03 nam 2004
																			  // Sua ngay 12 thang 09 nam 2005 chon diem peak cuoi
																			  // la diem chuyen giao giua Final Part va Silence
		///////////////////////////////////////////////
		// Bo xung cho am nang			//
		// ngay 15 thang 09 nam 2005	//
		//////////////////////////////////
		if(stSyllable.nTon == 6)
		{
			nOldSyllableLen		= stSyllable.nSyllableLen;
			stSyllable.nSyllableLen	= stSyllable.nSyllableLen + int(stPhone.lNewHandleLen/4)*BYTESPERSAMPLE; // Adding 1/2 length value of stPhone.lNewHandleLen;
			stPhone.lNewHandleLen	= int(3*stPhone.lNewHandleLen/4)*BYTESPERSAMPLE;
		}
		
		// Bo xung ngay 23 thang 03 nam 2005
		if (stPhone.lNewHandleLen <0)
		{
			stSyllable.nSyllableLen = stSyllable.nSyllableLen - 2*stPhone.lNewHandleLen;
			stPhone.lNewHandleLen = stSyllable.nSyllableLen - TempDip1.dwDipLen - TempDip2.lpPitchMarks[0]*2
				- (TempDip2.dwDipLen - TempDip2.lpPitchMarks[TempDip2.nNumberPitchMarks -1]);// Sua doi ngay 24 thang 03 nam 2004
																			  // Sua ngay 12 thang 09 nam 2005 chon diem peak cuoi
																			  // la diem chuyen giao giua Final Part va Silence
			delete [] stSyllable.lpNewSyllable;
			stSyllable.lpNewSyllable = new char[stSyllable.nSyllableLen];

						///////////////////////////////////////
			/*		bao loi ra ngoai file debug	 */
			///////////////////////////////////////
			CString strOut;
			strOut = "The length of synthetic unit is too short, you should increase";
			OutputLastError(strOut);
			////////////////////////////////////////
			
		}
		//KT bo xung
	}
	///////////////////////////////////////////////////////////////////////
	m_cTemplate = (char*)calloc(stSyllable.nSyllableLen + PSL_SAFEBUFFER * 2, sizeof(char));
		
	memset(m_cTemplate,0,stSyllable.nSyllableLen + PSL_SAFEBUFFER*2);
	
	stPhone.lpBuffer = m_cTemplate + PSL_SAFEBUFFER;// Con tro den vung dem moi, dung de chua phone moi
													// Vung dem PSL_SAFEBUFFER giup cho du lieu duoc an toan
	stPhone.lBufferMax = stSyllable.nSyllableLen;	// Do dai cuc dai cua vung dem moi 
	//////////////////////////////////////////////////////////////////////////////////////////////
	// For F0 generation automatically
	// Adding 24/12/2006 Recalculating and arranging the F0 array for the syllable
	//////////////////////////////////////////////////////////////////////////////////////////////
	if(BAutoORHandF0 ==2)	
	{
		int nNewNumberF0;
		int *nNewF0;
		int nF0Begin;
		
		nNewNumberF0 = stPhone.lNewHandleLen /BYTESPERSAMPLE/160;
		nF0Begin = stPhone.lHandlePoint/BYTESPERSAMPLE/160;
		
		if((nNewNumberF0 + nF0Begin)>stSyllable.nNumberFo) nNewNumberF0 = stSyllable.nNumberFo - nF0Begin;
		
		nNewF0 = new int[nNewNumberF0];
		for(int k= 0; k< nNewNumberF0; k++)
		{
			nNewF0[k] = stSyllable.nFo[nF0Begin + k];
		}
		delete [] stSyllable.nFo;
		stSyllable.nNumberFo = nNewNumberF0;
		stSyllable.nFo = new int[nNewNumberF0];
		memcpy(stSyllable.nFo,nNewF0,sizeof(int)*nNewNumberF0);
		delete [] nNewF0;

	}

	// End of For F0 generation automatically 24/12/2006
	//////////////////////////////////////////////////////////////////////////////////////////
	// Ngay 09 thang 09 nam 2005 
	// Bo xung them bien kieu Thanh dieu TonType
	//////////////////////////////////////////////////////////////////////////////////////////
	if(!CPsola::AccentFromPhone(TempDip1,TempDip2,stPhone,stSyllable.nFo,stSyllable.nNumberFo,stSyllable.nTon))  
	{
		////////////////////
		// Dua bao loi ra ngoai file debug.				
		////////////////////
		CString csTempOut1;
		csTempOut1 = CPsola::GetLastError();
		OutputLastError(csTempOut1);
		
		////////////////////
		delete[] TempDip1.lpBuffer;
		delete[] TempDip2.lpBuffer;
		delete[] TempDip1.lpPitchMarks;
		delete[] TempDip2.lpPitchMarks;
		delete[] m_cTemplate;
		//free(m_cTemplate);
		return FALSE;
	}

	// Bo xung ngay 04 thang 01 nam 2006 : Lay chieu dai that duoc ket noi 
	if(stSyllable.nSyllableLen > stPhone.lPhoneLen)
		stSyllable.nSyllableLen = stPhone.lPhoneLen;
	
	if((stSyllable.nTon == 6)&&(stSyllable.nSyllableLen > nOldSyllableLen)) // Do thanh 6 co chieu dai moi, nen can cap phat bo nho cho chieu dai moi
							 // Chieu dai cu khong dung duoc, va cau lenh cap phat bo nho truoc ko con phu hop
		{
			//if(stSyllable.nSyllableLen > nOldSyllableLen)
			delete [] stSyllable.lpNewSyllable;
			stSyllable.lpNewSyllable = new char[stSyllable.nSyllableLen];
		}
	
	// Bo xung ngay 04 thang 01 nam 2006 : Lay chieu dai that duoc ket noi 
	
	memcpy(stSyllable.lpNewSyllable,m_cTemplate + PSL_SAFEBUFFER,stSyllable.nSyllableLen);
	
	// Copy du lieu da duoc nao vao vao stSyllable.lpNewSyllable
	//////////////////////////////////////////////////////////////////////////
	//					Noi dung: Thay doi duong bao bien do 3 thanh dieu	//
	//							  Thanh nga, thanh hoi, thanh nang			//
	//////////////////////////////////////////////////////////////////////////
	if(stSyllable.nTon ==3) 
	{
		long nAmpLenHandle = 0;int i, ntempPos;
		int nFinalPartLen = 0;
	
		if(stPhone.fTransitionPoint > 0) 
			nFinalPartLen = int((1-stPhone.fTransitionPoint)*stSyllable.nSyllableLen/2)*BYTESPERSAMPLE;
		else 
		{
			nFinalPartLen = stSyllable.nSyllableLen - stPhone.lHandlePoint;
			stPhone.fTransitionPoint = float(stPhone.lHandlePoint)/stSyllable.nSyllableLen;
		}
		
		nAmpLenHandle = int(nFinalPartLen*17/100)*BYTESPERSAMPLE;
		
		double CoefMul = 0;
		for(i=0; i < nAmpLenHandle * 0.25; i+= BYTESPERSAMPLE)
		{
			CoefMul = (-2)*((double)i/(nAmpLenHandle)) + 1;
			
			ntempPos = int((stSyllable.nSyllableLen*stPhone.fTransitionPoint + 0.33*nFinalPartLen)/2)*BYTESPERSAMPLE +i;
			ChangeAmplitude(stSyllable.lpNewSyllable + ntempPos, 2,CoefMul);
			//ChangeAmplitude( + stDip1.lpPitchMarks[0]*BYTESPERSAMPLE + BYTESPERSAMPLE*(int)(0.125*nAmpLenHandle) +i,2,CoefMul);
		}

		for(i=0; i < nAmpLenHandle * 0.5; i+= BYTESPERSAMPLE)
		{
			CoefMul = 0.5;
			
			ntempPos = int((stSyllable.nSyllableLen*stPhone.fTransitionPoint + 0.33*nFinalPartLen)/2)*BYTESPERSAMPLE +
					   int(nAmpLenHandle/8)*BYTESPERSAMPLE +i;
			ChangeAmplitude(stSyllable.lpNewSyllable + ntempPos, 2,CoefMul);
			//ChangeAmplitude( + stDip1.lpPitchMarks[0]*BYTESPERSAMPLE + BYTESPERSAMPLE*(int)(0.125*nAmpLenHandle) +i,2,CoefMul);
		}
		for(i=0; i < nAmpLenHandle * 0.25; i+= BYTESPERSAMPLE)
		{
			CoefMul = (2)*((double)i/(nAmpLenHandle)) + 0.5;
			ntempPos = int((stSyllable.nSyllableLen*stPhone.fTransitionPoint + 0.33*nFinalPartLen)/2)*BYTESPERSAMPLE + 
					   int(nAmpLenHandle*3/8)*BYTESPERSAMPLE +i;
			ChangeAmplitude(stSyllable.lpNewSyllable + ntempPos, 2,CoefMul);
			//ChangeAmplitude(stPhone.lpBuffer + stDip1.lpPitchMarks[0]*BYTESPERSAMPLE + BYTESPERSAMPLE*(int)(0.25*nAmpLenHandle) +i ,2,CoefMul);
		}
	}
	if(stSyllable.nTon ==6) 
	{
		long nAmpLenHandle = 0;int i, ntempPos;
		int nFinalPartLen =0;

		if(stPhone.fTransitionPoint > 0) 
			nFinalPartLen = int((1-stPhone.fTransitionPoint)*stSyllable.nSyllableLen/2)*BYTESPERSAMPLE;
		else 
		{
			nFinalPartLen = stSyllable.nSyllableLen - stPhone.lHandlePoint;
			stPhone.fTransitionPoint = float(stPhone.lHandlePoint)/stSyllable.nSyllableLen;
		}
		
		nAmpLenHandle = int(nFinalPartLen*20/100)*BYTESPERSAMPLE;
	
		double CoefMul = 0;
		for(i=0; i < nAmpLenHandle * 0.5; i+= BYTESPERSAMPLE)
		{
			CoefMul = (-1.6)*((double)i/(nAmpLenHandle)) + 1;
			
			ntempPos = int((stSyllable.nSyllableLen*stPhone.fTransitionPoint + 0.30*nFinalPartLen)/2)*BYTESPERSAMPLE +i;
			ChangeAmplitude(stSyllable.lpNewSyllable + ntempPos, 2,CoefMul);
			//ChangeAmplitude( + stDip1.lpPitchMarks[0]*BYTESPERSAMPLE + BYTESPERSAMPLE*(int)(0.125*nAmpLenHandle) +i,2,CoefMul);
		}
		for(i=0; i < nAmpLenHandle * 0.5; i+= BYTESPERSAMPLE)
		{
			CoefMul = (1.6)*((double)i/(nAmpLenHandle)) + 0.2;
			//CoefMul = 0.67;
			ntempPos = int((stSyllable.nSyllableLen*stPhone.fTransitionPoint + 0.30*nFinalPartLen)/2)*BYTESPERSAMPLE + 
					   int(nAmpLenHandle/4)*BYTESPERSAMPLE +i;
			ChangeAmplitude(stSyllable.lpNewSyllable + ntempPos, 2,CoefMul);
			//ChangeAmplitude(stPhone.lpBuffer + stDip1.lpPitchMarks[0]*BYTESPERSAMPLE + BYTESPERSAMPLE*(int)(0.25*nAmpLenHandle) +i ,2,CoefMul);
		}
		
		nAmpLenHandle = nOldSyllableLen - int((stSyllable.nSyllableLen*stPhone.fTransitionPoint + 0.50*nFinalPartLen)/2)*BYTESPERSAMPLE;
		
		for(i=0; i < nAmpLenHandle; i+= BYTESPERSAMPLE)
		{
			CoefMul = (-1)*((double)i/(nAmpLenHandle)) + 1;// sua 1 -> 0.9
			ntempPos = int((stSyllable.nSyllableLen*stPhone.fTransitionPoint + 0.50*nFinalPartLen)/2)*BYTESPERSAMPLE +i;
			ChangeAmplitude(stSyllable.lpNewSyllable + ntempPos, 2,CoefMul);
			//ChangeAmplitude( + stDip1.lpPitchMarks[0]*BYTESPERSAMPLE + BYTESPERSAMPLE*(int)(0.125*nAmpLenHandle) +i,2,CoefMul);
		}


		if(nOldSyllableLen <  stSyllable.nSyllableLen)
		{

			char *TempDropSyllable = new char[stSyllable.nSyllableLen];
			memcpy(TempDropSyllable,stSyllable.lpNewSyllable,stSyllable.nSyllableLen);
			delete [] stSyllable.lpNewSyllable;
			stSyllable.nSyllableLen = nOldSyllableLen;
			stSyllable.lpNewSyllable = new char[stSyllable.nSyllableLen];
			memcpy(stSyllable.lpNewSyllable,TempDropSyllable,stSyllable.nSyllableLen);
		
			delete [] TempDropSyllable;

		}

	}

	/////////////////////////////////////////////////////////////////////////////////////
	///				Noi dung: Chuan hoa nang luong cua SYllable duoc tong hop	/////////
	/////////////////////////////////////////////////////////////////////////////////////	
	if(stSyllable.nEnergy > 0)
	{
		double Energy_coff = 2*(double)(stSyllable.nEnergy)/PSL_ENERGY_LEVELS;
		ChangeAmplitude(stSyllable.lpNewSyllable, stSyllable.nSyllableLen, Energy_coff);
	}

		
	for(counter=0; counter<nNumOfUnitPerSyl; counter++)
	{
		delete[] Unit[counter].lpBuffer;
		delete[] Unit[counter].lpPitchMarks;
	}
	
	free(m_cTemplate);

	if(B_EnergySmooth)
	{
		FP_OldSyl.nSignalLen = stSyllable.nSyllableLen;
		if(stPhone.fTransitionPoint ==0)
			FP_OldSyl.nTransPoint = FP_OldSyl.nPos[0];
		else
			FP_OldSyl.nTransPoint = (int)(stPhone.fTransitionPoint * stSyllable.nSyllableLen);
		if(stSyllable.nTon ==6)
		{
			for(int nNewNPitchMarks = 0; nNewNPitchMarks < FP_OldSyl.nNumberPos;nNewNPitchMarks++)
			{
				if(FP_OldSyl.nPos[nNewNPitchMarks] > nOldSyllableLen ) break;
			}

			FP_OldSyl.nNumberPos = nNewNPitchMarks;
		}
	}
	///////////////////////////////////////////////////////////////////////////////////
	

	//MessageBox(::AfxGetMainWnd()->m_hWnd, str,0,MB_OK);
	return TRUE;
}
/****************************************************************************************/
//////////////////////////////////////////////////////////////////////////////////////////
// sua doi ngay 21/10
// Ngay 09 thang 09 nam 2005 
// Bo xung bien : kieu Thanh dieu : nTonType
//				  Neu: nTonType co gia tri tu 1 - 8, Thanh dieu se duoc tong hop.
///////////////////////////////////////////////////////////////////////////////////////////////////////
//thaodv 200111 ?
BOOL CPsola::AccentFromPhone(UNITINFO &Dip1,UNITINFO &Dip2,PHONESTRUCT &stPhone, int *nFo, int nNumberFo, BYTE TonType)

{
	int *nTo;
	int *nSegmentLen;
	int nNumberTo;

	FRAMEPOSSTRUCT stFramePos;
	int nEndPoint;
	int *nLen; // Bo xung ngay 09/09/2005 
	////////////////////////////////////////////////////////////////////////////////////////
	//				Sua doi ngay 12 thang 11 nam 2004									  //
	//			Noi dung: sua de co the tong hop duoc ca loai INITIAL and FINAL			  //
	////////////////////////////////////////////////////////////////////////////////////////
	BOOL B_TypeCnFlag = TRUE; // true : Connecting 2 units with modifying the F0 of both
							// False : Connecting Initial and final parts
	BOOL B_F0zeroFlag = FALSE; // Dung de su dung cho truong hop tong hop am tiet, giu nguyen F0
							// gia tri TRUE the hien, am tiet se duoc the hien giong nguyen mau
	if(Dip1.nNumberPitchMarks == 0) B_TypeCnFlag = FALSE;

	if(BAutoORHandF0 <2)
	{
		if((TonType>0)&&(TonType<=8))
		{
			nNumberFo =	TonForSyllable(TonType,nF0_Begin, &nFo, &nLen, stPhone.lNewHandleLen,stPhone.fTransitionPoint);
			if(nNumberFo == -1) nNumberFo = 0;
		}
	}
	
	if(!nNumberFo) // check if F0 is given at the input parametes
	{
		if(B_TypeCnFlag)
		{
			DWORD Avg1 = GetAvgTo(Dip1.lpPitchMarks,Dip1.nNumberPitchMarks);// Lay gia tri trung binh cua T0 cua Dip1
			DWORD Avg2 = GetAvgTo(Dip2.lpPitchMarks,Dip2.nNumberPitchMarks);// Lay gia tri trung binh cua T0 cua Dip2
			nTo = new int [2];
			nTo[0] = (int)((Avg1+Avg2)/2);
			nNumberTo = 1;
			nSegmentLen = new int[2];
		}
		else // Sua doi ngay 12 thang 11 
		{
			DWORD Avg2 = GetAvgTo(Dip2.lpPitchMarks,Dip2.nNumberPitchMarks);// Lay gia tri trung binh cua T0 cua Dip2
			nTo = new int [2];
			nTo[0] = (int)(Avg2);
			nNumberTo = 1;
			nSegmentLen = new int[2];
			/////////////////////
			// tao co bao hieu co hieu chinh. Thuc te thi phan tren khong can, tam thoi giu lai //
			B_F0zeroFlag = TRUE;
		}


	}
	else
	{
		nNumberTo = nNumberFo;
		nTo = new int [nNumberTo];
		for(int i=0;i<nNumberTo;i++)
			nTo[i] = SAMPLERATE/nFo[i];
	}
	
	int nNumberPeak;// = Dip1.nNumberPitchMarks + Dip2.nNumberPitchMarks;
	
	if(B_TypeCnFlag)
		nNumberPeak = Dip1.nNumberPitchMarks + Dip2.nNumberPitchMarks;
	else 
		nNumberPeak = Dip2.nNumberPitchMarks;

	if(nNumberTo == 1) {
		
		//FRAMEPOSSTRUCT stFramePos;

		stFramePos.nStartPoint = stPhone.lHandlePoint;// Diem bat dau dinh vi cac Frame moi 
													  // Diem bat dau xu li cua stPhone
		stFramePos.nSignalLen = stPhone.lNewHandleLen;// Do dai vung dem can dinh vi cac Frame moi
													  // Do dai vung tin hieu moi sau khi hieu chinh
													  // tan so tu vung HandleLen
		stFramePos.nCount = stPhone.lNewHandleLen / (nTo[0] * BYTESPERSAMPLE) + 20; // Do dai cuc dai cua mang
													  // So Frame cuc dai 
		stFramePos.nPos = new int [stFramePos.nCount];// Mang chua vi tri Frame tinh duoc
		stFramePos.nAddition =0;
		/////////////////////////////////////////////////////////////////////////////////////////
		//			Sua doi de phu hop voi yeu cau bai toan, phan tich va tong hop nguoc	   //
		//			Ngay 25 thang 04 nam 2005												   //
		/////////////////////////////////////////////////////////////////////////////////////////
		if((!B_TypeCnFlag)&&(B_F0zeroFlag ==TRUE))
		{
			stFramePos.nNumberPos = Dip2.nNumberPitchMarks;
			for (int j = 0; j <stFramePos.nNumberPos; j++)
				stFramePos.nPos[j] = Dip1.dwDipLen + Dip2.lpPitchMarks[j]*BYTESPERSAMPLE;

		}
		else 
		{
			nEndPoint = SansAccentFromPhone(stFramePos,nTo[0]);
			// Sau lenh nay stFramePos da chua cac thong tin can thiet cua am ket noi moi
			// Lenh da thay doi vi tri cac khung vao vi tri moi voi T0 moi - Day moi chi la vi tri 
			// cua cac Frame con du lieu thi chua thuc hien ket noi
			if(nEndPoint == -1){
				delete[] stFramePos.nPos;
				delete[] nTo;
				OutputLastError("nEndPoint = -1");
				return FALSE;
			}
			
			stFramePos.nNumberPos++; // So Frame moi voi chu ky moi
			stFramePos.nPos[stFramePos.nNumberPos-1] = nEndPoint; // Diem ket thuc 
		}
		
		//Dip1.dwDipLen + Dip2.lpPitchMarks[Dip2.nNumberPitchMarks - 1] *2

		if(!CreateNewPhone(Dip1,Dip2,stPhone,stFramePos.nPos,stFramePos.nNumberPos))
		{
			delete[] stFramePos.nPos;
			delete[] nTo;
			OutputLastError("Create new Phone Error!");
			return FALSE;
		}
		delete[] stFramePos.nPos;
		delete[] nTo;
		return TRUE;
	}

			
	int nPos = stPhone.lHandlePoint;
	float fSignalLen;

	fSignalLen = float(stPhone.lNewHandleLen) / (nNumberTo-1);
	if(fSignalLen > (int(fSignalLen) +0.5f)) stFramePos.nSignalLen = int(fSignalLen) +1;
	else  stFramePos.nSignalLen = int(fSignalLen);
	int nTemp = GetMinValue(nTo,nNumberTo);

	if(nTemp == -1){
		delete[] nTo;
		OutputLastError("nTemp = -1");
		return FALSE;
	}

	nTemp = nTemp * BYTESPERSAMPLE;
	ASSERT(nTemp > 0);

	stFramePos.nCount = stPhone.lNewHandleLen /nTemp + 10;
	stFramePos.nNumberPos = 0;
	int *npPos = new int [stFramePos.nCount];
	stFramePos.nPos =  npPos;
	stFramePos.nStartPoint = stPhone.lHandlePoint;
	int nNumberPosition = 0;
	stFramePos.nAddition = 0;// 

	for(int j = 0; j < nNumberTo - 1; j++)
	{
		//////////////////////////////////////////////////////////////////////////
		// Ngay 09 thang 09 nam 2005
		// Bo xung dong lenh de lay F0 theo vi tri can dieu khien
		//////////////////////////////////////////////////////////////////////////
		if(BAutoORHandF0 < 2)// Adding 24/12/2006
			if((TonType>0)&&(TonType<=8)) stFramePos.nSignalLen = nLen[j];
		nPos = (nTo[j] < nTo[j+1])	? AccentGraveFromPhone(stFramePos,nTo[j],nTo[j+1])
									: AccentAiguFromPhone(stFramePos,nTo[j],nTo[j+1]);
		////////////////////////////////
		stFramePos.nAddition = stFramePos.nStartPoint + stFramePos.nAddition + stFramePos.nSignalLen - nPos;//

		/////////////////////////////////
		stFramePos.nStartPoint = nPos;
		stFramePos.nPos = stFramePos.nPos + stFramePos.nNumberPos;
		stFramePos.nCount -= stFramePos.nNumberPos;
		nNumberPosition += stFramePos.nNumberPos;
	}

	stFramePos.nPos = npPos;
	stFramePos.nNumberPos = nNumberPosition;
	stFramePos.nNumberPos++;
	stFramePos.nPos[stFramePos.nNumberPos-1] = nPos;

	if(!CreateNewPhone(Dip1,Dip2,stPhone,stFramePos.nPos,stFramePos.nNumberPos))
		{
		delete[] nTo;
		delete[] npPos;
		OutputLastError("Create New Phone 2 error!");
		return FALSE;
	}
	
	if(BAutoORHandF0 < 2)
		if((TonType>0)&&(TonType<=8)) delete[] nLen;
	delete[] npPos;
	delete[] nTo;
	return TRUE;
}

/****************************************************************************************/
BOOL CPsola::CreateNewPhone(UNITINFO stDip1,UNITINFO stDip2,PHONESTRUCT &stPhone,int *nFramePos,int nNumberFrames)
{
	int i;
	int nNearestPeakIndex;
	int nFrameLen; // chieu dai cua mot khung
	DWORD TempT;
	char *cFrame = new char [2];
	char *cFrame2= new char [2];
	BOOL MemforFrame2 = FALSE;
	
	//////////////////////////////////////////////////////////////////
	//		Bo xung ngay 12 thang 11 nam 2004						//
	//////////////////////////////////////////////////////////////////

	BOOL B_TypeCnFlag = TRUE; // true : Connecting 2 units with modifying the F0 of both
							// False : Connecting Initial and final parts
	if(stDip1.nNumberPitchMarks == 0) B_TypeCnFlag = FALSE;

	////////////////////////////////////////////////////////////////////
	double dStartCoef, dFinalCoef;

	if(B_TypeCnFlag == TRUE)
	{

	#define NUMBER_AMPLITUDE 2

		int t1,t2;
		//////////////////////////////////////////////////////////////////////
		// Bo xung ngay 05 thang 01 nam 2006: Sua doi noi dung lam tron		//
		//////////////////////////////////////////////////////////////////////
		long sMaxP1,sMaxP2,sMaxN1,sMaxN2;
		GetMaxPositiveValuePos(stDip1.lpBuffer + stDip1.lpPitchMarks[stDip1.nNumberPitchMarks - 2]*BYTESPERSAMPLE,stDip1.dwDipLen - stDip1.lpPitchMarks[stDip1.nNumberPitchMarks - 2]*BYTESPERSAMPLE,&sMaxP1);
		GetMaxNegativeValuePos(stDip1.lpBuffer + stDip1.lpPitchMarks[stDip1.nNumberPitchMarks - 2]*BYTESPERSAMPLE,stDip1.dwDipLen - stDip1.lpPitchMarks[stDip1.nNumberPitchMarks - 2]*BYTESPERSAMPLE,&sMaxN1);
		GetMaxPositiveValuePos(stDip2.lpBuffer, stDip2.lpPitchMarks[1]*BYTESPERSAMPLE, &sMaxP2);
		GetMaxNegativeValuePos(stDip2.lpBuffer, stDip2.lpPitchMarks[1]*BYTESPERSAMPLE, &sMaxN2);

		t1 = abs(sMaxP1 - sMaxN1)/2;
		t2 = abs(sMaxP2 - sMaxN2)/2;
		
		dStartCoef = fabs((double)m_wVolumeAmp / t1);
		dFinalCoef = fabs((double)m_wVolumeAmp / t2); // Dung khi ket noi binh thuong 
														// sua doi ngay 03/08/2005
	

	}
	else
	{
		
		dStartCoef = GetMaxAbsValue((short*)stDip1.lpBuffer, stDip1.dwDipLen/2);
		dFinalCoef = GetMaxAbsValue((short*)stDip2.lpBuffer, stDip2.dwDipLen/2);
		dStartCoef = fabs((double)m_wVolumeAmp / dStartCoef);
		dFinalCoef = fabs((double)m_wVolumeAmp / dFinalCoef);
		
	}
	
	//////////////////////////////////////////////////////////////////////////////////////
	//						Bo xung ngay 26 thang 10 nam 2004							//
	//////////////////////////////////////////////////////////////////////////////////////
	int Max1 = 0, Max2 =0;
	double Max = 0;
	

	int nNumberPeaks, nMaxFrameLen;
	
	if(B_TypeCnFlag)
	{
		// tam thoi chua dung vi da su dung tren ham test phia tren 25/04/2005
		if((!ChangeAmplitude( stDip1.lpBuffer ,stDip1.dwDipLen, dStartCoef))||
		(!ChangeAmplitude(stDip2.lpBuffer ,stDip2.dwDipLen,dFinalCoef)))
		{
			OutputLastError("Change Amplitude Error!");
			return FALSE;
		}
		//////////////////////////////////////////////////////////////////////
		Max1 = GetMaxTo(stDip1.lpPitchMarks,stDip1.nNumberPitchMarks);
		Max2 = GetMaxTo(stDip2.lpPitchMarks,stDip2.nNumberPitchMarks);
		nMaxFrameLen = ((Max1 > Max2 ? Max1 : Max2)*2 + 1)*BYTESPERSAMPLE; 
																		// Tai sao o day nhan 2.
																		// Tao bo dem co kich 
																		// thuoc lon 2 lan cai Max
																		// DAM BAO LAY 2 CHU KY

		stDip1.nNumberPitchMarks--;
		stDip2.nNumberPitchMarks--;
				
		nNumberPeaks = stDip1.nNumberPitchMarks + stDip2.nNumberPitchMarks;
		nNumberPeaks--;
		BOOL BNewWindow;
		int nNextPeakIndex, nNumberOfWindow, nWinCounter, nNextPeakIndexOld;
		float fCoefMapping;
		BNewWindow = FALSE;
		nWinCounter =-1;

		for(i = 0; i < nNumberFrames; i++)  // i chay tu 0 toi so Frames duoc dua tu dau vao, 
											//so Frame nay da duoc tinh theo T0 moi
		{
				///////Tim dinh gan nhat
			float fNearestPeakIndex;
			fNearestPeakIndex = (float)i/ (nNumberFrames-1) * (nNumberPeaks-1);
			nNearestPeakIndex = int((float)i/ (nNumberFrames-1) * (nNumberPeaks-1));
			if(fNearestPeakIndex > float(nNearestPeakIndex) + 0.5f) nNearestPeakIndex++;
			if((BNewWindow == FALSE)&&(i<nNumberFrames))//+1))
			{
				int k;
				k=i+1;
				for(;;)
				{
					fNearestPeakIndex = (float)k/ (nNumberFrames-1) * (nNumberPeaks-1);
					nNextPeakIndex = int((float)k/ (nNumberFrames-1) * (nNumberPeaks-1));
					if(fNearestPeakIndex > float(nNextPeakIndex) + 0.5f) nNextPeakIndex++;
					if(nNextPeakIndex>= nNearestPeakIndex +1)
					{
						if(k >= i+2)
						{
							nNumberOfWindow = k -i;
							fCoefMapping	= 1.0f/(nNumberOfWindow);
							BNewWindow		= TRUE;
							nWinCounter		=0;
							nNextPeakIndexOld	= nNextPeakIndex;
						}
						break;
					}
					k++;
				}
			}
			
			////////Lay cua so Hanning Window
			delete[] cFrame; 
			cFrame = new char [nMaxFrameLen]; // Tao mang cho cFrame
			memset(cFrame,0,nMaxFrameLen);
		
			if(nNearestPeakIndex < stDip1.nNumberPitchMarks) //? Y nghia cua phep kiem tra nay?
																 // Kiem tra diem Peak dau tien co vuot
																 // qua duoc so diem Pitch cua AUnit 1 
																 // hay khong, so diem Peak hien tai 
																 // tinh cho ca Syllable ( thuc chat la
																 // cua 2 doan ket noi
			{
				TempT =	stDip1.lpPitchMarks[nNearestPeakIndex+1]-
							stDip1.lpPitchMarks[nNearestPeakIndex];// Lay khoang cach hai dinh ke nhau lay 
				nFrameLen = (TempT*2 + 1)* BYTESPERSAMPLE;	// Chieu dai bo dem // CHU Y DO DAI KHUNG NHAN 2 DE LAY 
																				// CHU KY. DUNG DE CONG TIN HIEU
				/////////////////////////////////////////////////////////////////////////////////////////
				/////////////// Sua doi ngay 07/03/2005 //////////////////////////////////////////////////////
				if(TempT < stDip1.lpPitchMarks[nNearestPeakIndex] )
					memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2,
					stDip1.lpBuffer + stDip1.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE -TempT * BYTESPERSAMPLE,nFrameLen );
				else
				{	
					memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2 + 
						(TempT - stDip1.lpPitchMarks[nNearestPeakIndex])*BYTESPERSAMPLE,
						stDip1.lpBuffer, stDip1.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE);
					
					/////////////////////////////////////////////////////////////////////////////////
					// sua ngay 15 thang 04
					memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2 + TempT*BYTESPERSAMPLE,
							stDip1.lpBuffer + stDip1.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE,
							TempT * BYTESPERSAMPLE);
				}
			/////////////////////////////////////////////////////////////////////////////////////////
				
			}
			else	// Neu diem Peak gan nhat vuot qua so diem Pitch cua AUnit 1
					// thi bat dau tai vi tri dau tien cua diem peak cua AUnit 1
			{
				nNearestPeakIndex = nNearestPeakIndex - stDip1.nNumberPitchMarks+1;
				TempT = stDip2.lpPitchMarks[nNearestPeakIndex+1]
							-stDip2.lpPitchMarks[nNearestPeakIndex];
				nFrameLen = (TempT*2 + 1)* BYTESPERSAMPLE;
				

				if(TempT < stDip2.lpPitchMarks[nNearestPeakIndex] )
					memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2,
					stDip2.lpBuffer + stDip2.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE -TempT * BYTESPERSAMPLE,nFrameLen );
				else
				{	
					memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2 + 
						(TempT - stDip2.lpPitchMarks[nNearestPeakIndex])*BYTESPERSAMPLE,
						stDip2.lpBuffer, stDip2.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE);
					memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2 + TempT*BYTESPERSAMPLE,
						stDip2.lpBuffer + stDip2.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE,
						TempT*BYTESPERSAMPLE);

				}

			}
				// Hai tap lenh tren dua du lieu vao vi tri cua cac khung thuoc T0 moi
			HanningWnd( cFrame + (nMaxFrameLen - nFrameLen)/2 , nFrameLen);

			if((BNewWindow == TRUE)&&(nWinCounter > 0))
			{
				delete[] cFrame2; 
				//MemforFrame2 = FALSE;
				cFrame2 = new char [nMaxFrameLen]; // Tao mang cho cFrame2
				MemforFrame2 = TRUE;
				memset(cFrame2,0,nMaxFrameLen);
				nNextPeakIndex = nNextPeakIndexOld;
				if(nNextPeakIndex < stDip1.nNumberPitchMarks) 
				{
					memcpy(cFrame2 + (nMaxFrameLen - nFrameLen)/2,
						stDip1.lpBuffer + stDip1.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE -TempT * BYTESPERSAMPLE,nFrameLen );
										
				}
				else	// Neu diem Peak gan nhat vuot qua so diem Pitch cua AUnit 1
						// thi bat dau tai vi tri dau tien cua diem peak cua AUnit 1
				{
					if(nNextPeakIndex > stDip1.nNumberPitchMarks)
					{
						nNextPeakIndex = nNextPeakIndex - stDip1.nNumberPitchMarks+1;
						TempT = stDip2.lpPitchMarks[nNearestPeakIndex+1] - stDip2.lpPitchMarks[nNearestPeakIndex];
						nFrameLen = (TempT*2 + 1)* BYTESPERSAMPLE;
					}
					else nNextPeakIndex = nNextPeakIndex - stDip1.nNumberPitchMarks+1;
					
					if(TempT < stDip2.lpPitchMarks[nNextPeakIndex] )
					{
						if((stDip2.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE + nFrameLen/2)<stDip2.dwDipLen)
						memcpy(cFrame2 + (nMaxFrameLen - nFrameLen)/2, 
						stDip2.lpBuffer + stDip2.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE -TempT * BYTESPERSAMPLE,nFrameLen );
						else
						{
							memcpy(cFrame2 + (nMaxFrameLen - nFrameLen)/2, 
							stDip2.lpBuffer + stDip2.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE -TempT * BYTESPERSAMPLE,
							stDip2.dwDipLen - stDip2.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE + TempT );

						}
								
					}
					else
					{	
						memcpy(cFrame2 + (nMaxFrameLen - nFrameLen)/2 + 
							(TempT - stDip2.lpPitchMarks[nNextPeakIndex])*BYTESPERSAMPLE,
							stDip2.lpBuffer, stDip2.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE);
						memcpy(cFrame2 + (nMaxFrameLen - nFrameLen)/2 + TempT*BYTESPERSAMPLE,
							stDip2.lpBuffer + stDip2.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE,
							TempT*BYTESPERSAMPLE);
					}

				}

				HanningWnd( cFrame2 + (nMaxFrameLen - nFrameLen)/2 , nFrameLen);
				for(int j = 0; j < nMaxFrameLen; j+= BYTESPERSAMPLE )
				*(short *)(cFrame + j) = short((*(short *)(cFrame + j))*(1.0f-fCoefMapping*nWinCounter) + (*(short *)(cFrame2 + j))*fCoefMapping*nWinCounter);
				nWinCounter++;
				
			}
			if((BNewWindow == TRUE)&&(nWinCounter == 0)) nWinCounter++;
						
			for(int j = 0; j < nMaxFrameLen; j+= BYTESPERSAMPLE )
				*(short *)(stPhone.lpBuffer + nFramePos[i] + j - (nMaxFrameLen - BYTESPERSAMPLE)/2) += *(short *)(cFrame + j);
									// Cong du lieu vao trong stPhone la du lieu can dua ra.

			if((BNewWindow == TRUE)&&(nWinCounter == nNumberOfWindow))
			{
				BNewWindow = FALSE;
				nWinCounter = 0;
			}

		}

		memcpy(stPhone.lpBuffer,stDip1.lpBuffer,stDip1.lpPitchMarks[0]*BYTESPERSAMPLE);
		
		// Thay doi khong dung cau lenh tren tu ngay 04/08/2005
		memcpy(stPhone.lpBuffer + nFramePos[nNumberFrames -1],stDip2.lpBuffer + stDip2.lpPitchMarks[stDip2.nNumberPitchMarks -1]*BYTESPERSAMPLE,
				stDip2.dwDipLen - stDip2.lpPitchMarks[stDip2.nNumberPitchMarks -1]*BYTESPERSAMPLE);
		// Lay chieu dai thuc te cua Syllable duoc ket noi.

		stPhone.lPhoneLen = nFramePos[nNumberFrames - 1] + stDip2.dwDipLen - stDip2.lpPitchMarks[stDip2.nNumberPitchMarks -1]*BYTESPERSAMPLE;

	}
	else
	{
		// thu chuan hoa nang luong ve nguong 20000
		double dCommonCoef = 0;
		dCommonCoef = (dStartCoef < dFinalCoef ) ? dStartCoef : dFinalCoef;
		
		//////////////////////////////////////////////////////////////////////////////////////
		// Test thu viec chuan hoa nang luong, ngay 25/04/2005
		if((!ChangeAmplitude( stDip1.lpBuffer ,stDip1.dwDipLen, dCommonCoef))||
			(!ChangeAmplitude(stDip2.lpBuffer ,stDip2.dwDipLen,dCommonCoef)))
		{
			OutputLastError("Change Amplitude 02 Error!");
			return FALSE;
		}
		////////////////////// ket thuc chuan hoa
		
		Max2 = GetMaxTo(stDip2.lpPitchMarks,stDip2.nNumberPitchMarks);
		nMaxFrameLen = (Max2*2 + 1)*BYTESPERSAMPLE; 
		stDip2.nNumberPitchMarks--;		
		
		nNumberPeaks = stDip2.nNumberPitchMarks;
		BOOL BNewWindow;
		int nNextPeakIndex, nNumberOfWindow, nWinCounter, nNextPeakIndexOld;
		float fCoefMapping;
		BNewWindow = FALSE;
		nWinCounter =-1;	

		for(i = 0; i < nNumberFrames; i++)  // i chay tu 0 toi so Frames duoc dua tu dau vao, 
											//so Frame nay da duoc tinh theo T0 moi
		{
			//Tim dinh gan nhat

			float fNearestPeakIndex;
			fNearestPeakIndex = (float)i/ (nNumberFrames-1) * (nNumberPeaks-1);
			nNearestPeakIndex = int((float)i/ (nNumberFrames-1) * (nNumberPeaks-1));
			if(fNearestPeakIndex > float(nNearestPeakIndex) + 0.5f) nNearestPeakIndex++;
			if((BNewWindow == FALSE)&&(i<nNumberFrames))//+1))
			{
				int k;
				k=i+1;
				for(;;)
				{
					fNearestPeakIndex = (float)k/ (nNumberFrames-1) * (nNumberPeaks-1);
					nNextPeakIndex = int((float)k/ (nNumberFrames-1) * (nNumberPeaks-1));
					if(fNearestPeakIndex > float(nNextPeakIndex) + 0.5f) nNextPeakIndex++;
					if(nNextPeakIndex>= nNearestPeakIndex +1)
					{
						if(k >= i+2)
						{
							nNumberOfWindow = k -i;
							fCoefMapping	= 1.0f/(nNumberOfWindow);
							BNewWindow		= TRUE;
							nWinCounter		=0;
							nNextPeakIndexOld	= nNextPeakIndex;
						}
						break;
					}
					k++;
				}
			}
		
			////////Lay cua so Hanning Window
			delete[] cFrame; 
			cFrame = new char [nMaxFrameLen]; // Tao mang cho cFrame
			memset(cFrame,0,nMaxFrameLen); 

			TempT = stDip2.lpPitchMarks[nNearestPeakIndex+1] - stDip2.lpPitchMarks[nNearestPeakIndex];
			
			nFrameLen = (TempT*2 + 1)* BYTESPERSAMPLE;
			
			//******************* Bo xung ngay 07/02/2005 ********************************//
			//	Noi dung: Kiem tra vi tri cua con tro du lieu neu khong con tro se chi  **//
			//			  vao vi tri truoc cua mang										**//
			//****************************************************************************//

			if(TempT < stDip2.lpPitchMarks[nNearestPeakIndex] )
			memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2,
					stDip2.lpBuffer + stDip2.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE -
					TempT * BYTESPERSAMPLE,nFrameLen );
			else
			{	
				memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2 + 
					(TempT - stDip2.lpPitchMarks[nNearestPeakIndex])*BYTESPERSAMPLE,
					stDip2.lpBuffer, stDip2.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE);
			
				/////////////////////////////////////////////////////////////////////////////////
				// sua ngay 15 thang 04 nam 2005
				memcpy(cFrame + (nMaxFrameLen - nFrameLen)/2 + TempT*BYTESPERSAMPLE,
							stDip2.lpBuffer + stDip2.lpPitchMarks[nNearestPeakIndex]*BYTESPERSAMPLE,
							TempT * BYTESPERSAMPLE);
			}

				// Copy du lieu tu vi tri khung can chep cua AUnit2 vao cFrame
				// Hai tap lenh tren dua du lieu vao vi tri cua cac khung thuoc T0 moi

			HanningWnd( cFrame + (nMaxFrameLen - nFrameLen)/2 , nFrameLen);

			if((BNewWindow == TRUE)&&(nWinCounter > 0))
			{
				delete[] cFrame2; 
				cFrame2 = new char [nMaxFrameLen]; // Tao mang cho cFrame2
				memset(cFrame2,0,nMaxFrameLen);
				nNextPeakIndex = nNextPeakIndexOld;
			
				memcpy(cFrame2 + (nMaxFrameLen - nFrameLen)/2, 
						stDip2.lpBuffer + stDip2.lpPitchMarks[nNextPeakIndex]*BYTESPERSAMPLE -TempT * BYTESPERSAMPLE,nFrameLen );
				
				HanningWnd( cFrame2 + (nMaxFrameLen - nFrameLen)/2 , nFrameLen);
				for(int j = 0; j < nMaxFrameLen; j+= BYTESPERSAMPLE )
				*(short *)(cFrame + j) = short((*(short *)(cFrame + j))*(1.0f-fCoefMapping*nWinCounter) + (*(short *)(cFrame2 + j))*fCoefMapping*nWinCounter);
				nWinCounter++;
			}
			if((BNewWindow == TRUE)&&(nWinCounter == 0)) nWinCounter++;
			
			for(int j = 0; j < nMaxFrameLen; j+= BYTESPERSAMPLE )
				*(short *)(stPhone.lpBuffer + nFramePos[i] + j - (nMaxFrameLen - BYTESPERSAMPLE)/2) += *(short *)(cFrame + j);
									// Cong du lieu vao trong stPhone la du lieu can dua ra.
			if((BNewWindow == TRUE)&&(nWinCounter == nNumberOfWindow))
			{
				BNewWindow = FALSE;
				nWinCounter = 0;
			}
		}
		
		memcpy(stPhone.lpBuffer,stDip1.lpBuffer,stDip1.dwDipLen);
		memcpy(stPhone.lpBuffer + stDip1.dwDipLen,stDip2.lpBuffer,stDip2.lpPitchMarks[0]*BYTESPERSAMPLE);
		memcpy(stPhone.lpBuffer + nFramePos[nNumberFrames -1],stDip2.lpBuffer + stDip2.lpPitchMarks[stDip2.nNumberPitchMarks -1]*BYTESPERSAMPLE,
				stDip2.dwDipLen - stDip2.lpPitchMarks[stDip2.nNumberPitchMarks -1]*BYTESPERSAMPLE);

		stPhone.lPhoneLen = nFramePos[nNumberFrames - 1] + stDip2.dwDipLen - stDip2.lpPitchMarks[stDip2.nNumberPitchMarks -1]*BYTESPERSAMPLE;

		
	}
	//////////////////////////////////////////////////////////////////////////////
	// Bo xung ngay 01 thang 01 nam 2006	//
	//////////////////////////////////////////

	if(B_EnergySmooth)
	{
		FP_OldSyl.nPos = new int[nNumberFrames];
		FP_OldSyl.nNumberPos = nNumberFrames;
		memcpy(FP_OldSyl.nPos, nFramePos, nNumberFrames*sizeof(int));
	}

	//////////////////////////////////////////
	
	//if(MemforFrame2 == TRUE) delete[] cFrame2; 
	delete[] cFrame2; 
	delete[] cFrame;
	return TRUE;
}
/****************************************************************************************/


int CPsola::TonForSyllable(BYTE TonType, int F0, int **nF0, int **nLen, int nLenOfSyl, float fTransitionPoint)
{
	// Bo xung ngay 23 thang 06 nam 2005 
	// Them ton 7 va 8 danh cho thanh Saac 5b va thanh nang 6b
	if ((TonType<1) ||(TonType>8)) return -1;
	int nNumOfCtrlPoint = 0;
	int counter = 0;
	
	int nValueOfF0_1[4] =	{100,100,100, 90};
	int nValueOfF0_2[4] =	{100, 95, 80, 75};
	int nValueOfF0_3[8] = 	{100, 95, 85, 50, 50, 95, 120, 125};
	int nValueOfF0_4[5] =	{100, 90, 75, 65, 90};
	int nValueOfF0_5[4] =	{100,100,110, 125};
	int nValueOfF0_6[5]	=	{100, 95, 85, 55, 50};
	int nValueOfF0_7[3] =	{100,110, 125};
	int nValueOfF0_8[3] =	{100, 88, 65};
	

	int nCtrlPosition_1[3] = {33,34,33};
	int nCtrlPosition_2[4] = {25,25,25,25};
	int nCtrlPosition_3[7] = {16, 17,8,18,8,17,16};
	int nCtrlPosition_6[4] = {20,15,15,50};
	int nCtrlPosition_7[2] = {40,60};

	int lTransitionPoint;
	lTransitionPoint = fTransitionPoint*nLenOfSyl;
	nLenOfSyl = nLenOfSyl - lTransitionPoint;
	delete [] *nF0;

	if (TonType == 1)
	{
		nNumOfCtrlPoint = 5;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];

		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_1[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_1[counter-1]/100;
	
	}
	if (TonType == 2)
	{
		F0 = F0*92/100;
		nNumOfCtrlPoint = 5;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];

		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_2[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_1[counter-1]/100;		
		
	}

	if (TonType == 3)
	{
		F0 = F0*95/100;
		nNumOfCtrlPoint = 9;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];
		
		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_3[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_3[counter-1]/100;
	
	}

	if (TonType == 4)
	{
		F0 = F0*92/100;
		nNumOfCtrlPoint = 6;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];
		
		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_4[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_2[counter-1]/100;
		
	}
	
	if (TonType == 5)
	{
		F0 = F0*92/100;
		nNumOfCtrlPoint = 5;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];
		
		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_5[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_1[counter-1]/100;
	
	}

	if (TonType == 6)
	{
		F0 = F0*90/100;
		nNumOfCtrlPoint = 6;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];
		
		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_6[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_6[counter-1]/100;
	
	}

	if (TonType == 7)
	{
		nNumOfCtrlPoint = 4;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];

		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_7[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_7[counter-1]/100;
	
	}

	if (TonType == 8)
	{
		nNumOfCtrlPoint = 4;
		*nF0 = new int[nNumOfCtrlPoint];
		*nLen = new int[nNumOfCtrlPoint - 1];

		for(counter = 1; counter < nNumOfCtrlPoint;counter++)
			(*nF0)[counter] = F0*nValueOfF0_8[counter-1]/100;
		for(counter = 1; counter < nNumOfCtrlPoint-1;counter++)
			(*nLen)[counter] = nLenOfSyl*nCtrlPosition_7[counter-1]/100;
	
	}



	(*nF0)[0] = F0*98/100;
	(*nLen)[0] = lTransitionPoint;
	if((*nLen)[0] ==0)
	{
		for(counter=0; counter < nNumOfCtrlPoint - 1; counter++)
			(*nF0)[counter] = (*nF0)[counter+1];
		for(counter=0; counter < nNumOfCtrlPoint - 2; counter++)
			(*nLen)[counter] = (*nLen)[counter+1];
		nNumOfCtrlPoint --;
	}

	
	return nNumOfCtrlPoint;

}



//==========================================================================================================
// The below function smooths the discontinution of energy between two adjacent syllables by  TD-PSOLA methode
//==========================================================================================================
// thaodv 200111 ?
BOOL CPsola::EnergySmooth(FRAMEPOSSTRUCT PreSyl, FRAMEPOSSTRUCT CurSyl, SYLLABLESTRUCT &Syl)
{
	int nTo1, nTo2, nWindowSize;
	double CoefMul = 0;
	
	nTo1 = (CurSyl.nPos[1] - CurSyl.nPos[0])/BYTESPERSAMPLE;
	nTo2 = (PreSyl.nPos[PreSyl.nNumberPos -1] - PreSyl.nPos[PreSyl.nNumberPos -2])/BYTESPERSAMPLE;

	if(nTo1>nTo2) nWindowSize = 2*nTo1;
	else nWindowSize = 2*nTo2;

	CWaveFile fWaveFile;
	if(!fWaveFile.Attach(CsNameOfWavFile))
	{
		m_nErrorCode = PSL_WF_ERROR;
		OutputLastError(GetLastError());
		return FALSE;
	}
	
	DWORD dwSize = fWaveFile.GetDataSize();
	char *lpWave = new char [dwSize];
	if(!fWaveFile.SeparateData(lpWave,NULL,dwSize))
	{
		m_nErrorCode = PSL_WF_ERROR;
		delete[] lpWave;
		OutputLastError(GetLastError());
		return FALSE;
	}
	

	char *lpWindowTemp = new char [nWindowSize*BYTESPERSAMPLE + 400];
	memset(lpWindowTemp,0,nWindowSize*BYTESPERSAMPLE + 400);

	memcpy(lpWindowTemp + 200,Syl.lpNewSyllable, nWindowSize*BYTESPERSAMPLE);
	HanningWnd(lpWindowTemp, nWindowSize*BYTESPERSAMPLE);
		
	CoefMul = 0.9;
	for(int nCounter =0; nCounter< nWindowSize*BYTESPERSAMPLE; nCounter += BYTESPERSAMPLE) 
	{
		*(short *)(lpWave + dwSize - 2*nWindowSize*BYTESPERSAMPLE + nCounter) = *(short *)(lpWave + dwSize - 2*nWindowSize*BYTESPERSAMPLE + nCounter)*CoefMul
																					+ *(short *)(lpWindowTemp + 200 +nCounter) * (1-CoefMul);
	}
	CoefMul = 0.75;
	for(nCounter =0; nCounter< nWindowSize*BYTESPERSAMPLE; nCounter += BYTESPERSAMPLE) 
	{
		*(short *)(lpWave + dwSize - 3*nWindowSize + nCounter) = *(short *)(lpWave + dwSize - 3*nWindowSize + nCounter)*CoefMul
																					+ *(short *)(lpWindowTemp + 200 +nCounter) * (1-CoefMul);
	}
	CoefMul = 0.6;
	for(nCounter =0; nCounter< nWindowSize*BYTESPERSAMPLE; nCounter += BYTESPERSAMPLE)
	{
		*(short *)(lpWave + dwSize - nWindowSize*BYTESPERSAMPLE + nCounter) = *(short *)(lpWave + dwSize - nWindowSize*BYTESPERSAMPLE + nCounter)*CoefMul
																					+ *(short *)(lpWindowTemp + 200 +nCounter) * (1-CoefMul);
	}
	CoefMul = 0.5;
	for(nCounter =0; nCounter< nWindowSize; nCounter += BYTESPERSAMPLE)
	{
		*(short *)(lpWave + dwSize - int(nWindowSize/2)*BYTESPERSAMPLE + nCounter) = *(short *)(lpWave + dwSize - int(nWindowSize/2)*BYTESPERSAMPLE + nCounter)*CoefMul
																					+ *(short *)(lpWindowTemp + 200 +nCounter) * (1-CoefMul);
	}

	memset(lpWindowTemp,0,nWindowSize*BYTESPERSAMPLE + 400);

	memcpy(lpWindowTemp + 200,lpWave + dwSize - nWindowSize*BYTESPERSAMPLE, nWindowSize*BYTESPERSAMPLE);
	HanningWnd(lpWindowTemp, nWindowSize*BYTESPERSAMPLE);

	CoefMul = 0.5;
	for(nCounter =0; nCounter< nWindowSize; nCounter += BYTESPERSAMPLE)
	{
		*(short *)(Syl.lpNewSyllable + nCounter) = *(short *)(Syl.lpNewSyllable + nCounter)*CoefMul
													+ *(short *)(lpWindowTemp + 200 +int(nWindowSize/2)*BYTESPERSAMPLE+ nCounter) * (1-CoefMul);
	}
	CoefMul = 0.6;
	for(nCounter =0; nCounter< nWindowSize*BYTESPERSAMPLE; nCounter += BYTESPERSAMPLE)
	{
		*(short *)(Syl.lpNewSyllable + nCounter) = *(short *)(Syl.lpNewSyllable + nCounter)*CoefMul
													+ *(short *)(lpWindowTemp + 200 +nCounter) * (1-CoefMul);
	}

	CoefMul = 0.75;
	for(nCounter =0; nCounter< nWindowSize*BYTESPERSAMPLE; nCounter += BYTESPERSAMPLE)
	{
		*(short *)(Syl.lpNewSyllable + nWindowSize+ nCounter) = *(short *)(Syl.lpNewSyllable + nWindowSize + nCounter)*CoefMul
													+ *(short *)(lpWindowTemp + 200 +nCounter) * (1-CoefMul);
	}
	CoefMul = 0.9;
	for(nCounter =0; nCounter< nWindowSize*BYTESPERSAMPLE; nCounter += BYTESPERSAMPLE)
	{
		*(short *)(Syl.lpNewSyllable + nWindowSize*BYTESPERSAMPLE+ nCounter) = *(short *)(Syl.lpNewSyllable + nWindowSize*BYTESPERSAMPLE + nCounter)*CoefMul
													+ *(short *)(lpWindowTemp + 200 +nCounter) * (1-CoefMul);
	}

	
	if(!CWaveFile::CreateWaveFile(CsNameOfWavFile,SAMPLERATE,BITSPERSAMPLE,1,dwSize,lpWave))
	{
		delete[] lpWave;
		m_nErrorCode = PSL_WF_ERROR;
		OutputLastError(GetLastError());
		return FALSE;
	}

	delete[] lpWindowTemp;
	delete[] lpWave;


	
	return TRUE;
}

///////////////////////////////////////////////////////////////////////
		/*		bao loi ra ngoai file debug	 */
//////////////////////////////////////////////////////////////////////
BOOL CPsola::OutputLastError(CString strOut)
{
		
	FILE* fp;
	if((fp = fopen(CPsola::CsNameOfDebugFile,"a")) == NULL) 
	{
		return FALSE;
	}
	else
	{
		strOut = strOut +"\n";
		fputs(strOut, fp);
		fclose(fp);	
		return TRUE;
	}
}


